На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Запрещается обсуждать написание вирусов, троянов и других вредоносных программ!
2. Помните, что у нас есть FAQ раздела Assembler и Полезные ссылки. Посмотрите, возможно, там уже имеется решение вашего вопроса.

3. Настоятельно рекомендуем обратить особое внимание на правила форума, которые нарушаются чаще всего:
  3.1. Заголовок темы должен кратко отражать её суть. Темы с заголовками типа "Срочно помогите!" или "Ассемблер" будут отправляться в Корзину для мусора.
  3.2. Исходники программ обязательно выделяйте тегами [code]...[/code] (одиночные инструкции можно не выделять).
  3.3. Нежелательно поднимать старые темы (не обновлявшиеся более года) без веской на то причины.

Не забывайте также про главные Правила форума!

Добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: Jin X, Qraizer
  
> сопроцессор , вещественная арифметика
    Помогите разобратся:
    ExpandedWrap disabled
      ...
      ;набрали 1-е число:  GetWindowTextA@12 --> eax
      ...
       plus:                ;нажали "+" (id_But equ 1Ch)
         mov   edx,0        ;очищаем регистр
         mov   edx,1Ch      ;отмечаем нажатую кнопку  
         mov   str1,eax     ;сохраняем что набрали
         finit              ;инициируем сопроцессор
         fldz               ;очищаем вершину стека 0-->st(0)
         fld   str1         ;добавляем первое число str1-->st(0)
         call  clear        ;очищаем дисплей  
      ...
      ;набрали 2-е число:  GetWindowTextA@12 --> eax
      ...
       itog:                     ;нажали "="
         cmp edx,1Ch                            
         je  plus_ex
      ...
      plus_ex:
         call  clear             ;очищаем дисплей
         mov   buf,0             ;очищаем буфер ?
         mov   str2,eax          ;сохраняем что набрали
         finit                   ;инициируем сопроцессор
         fadd  str2              ;st(0)+str2-->st(0)
         fst   buf               ;st(0)-->buf - здесь сумма
         push  offset buf        
         push  [hWndEdt]
         call  SetWindowTextA@8  ;выводим сумму на дисплей
         jmp   exit              ;mov eax,0  jmp finish
      ...
      finish:
        pop  edi
        pop  esi
        pop  ebx
        pop  ebp
        ret  16
      winproc endp
      clear  proc
        push  Edt
        push  [hWndEdt]
        call  SetWindowTextA@8
        ret
      clear  endp
      end go


    В результате сложения (после нажатия "=") - на дисплее последнее набранное число. Такое впечатление, что первое число в st(0) не попало (fld str1) или, почему-то, от туда исчезло. Даже без конвертации что-то должно быть.
    Сообщение отредактировано: Qraizer -
      Как бы негоже проводить инициализацию на каждый раз. Так, в Винде на 32-битах у меня вообще пишет недопустимую операцию при добавлении числа к пустой ячейке. В 16-битном режиме что-то складывает с давно там записанным. :yes-sad:
        finit уничтожает все данные во всех (в т.ч. специальных) регистрах сопроцессора. К незанятому регистру FPU ничего нельзя прибавить. В FPU есть специальные регистры-теги, которые хранят доп.информацию об основных стековых регистрах. Если регистр помечен как незанятый, то и результат будет "никаким".

        Цитата cupoma58 @
        Даже без конвертации что-то должно быть.
        Если вы пытаетесь записать в st(0) строку, то там явно будет не то, что нужно. И это "что-то" может быть, например, NaN (нечисло) или Inf (бесконечность).

        p.s. jmp exit или finish?
          Цитата Jin X @
          finit уничтожает все данные во всех (в т.ч. специальных) регистрах сопроцессора.
          У меня книга "Assembler для Dos, Windows и Unix" (Москва, 1999) пишет:
          Цитата
          FINIT: ... Регистры данных никак не изменяются, но все они помечаются пустыми в регистре TW.
          Собственно, 16-битный запуск подтвердил, что если после finit'а идёт сразу fadd, то происходит прибавление чего-то с чем-то. А вот Винда 32-битная пишет "1#IND" в регистре. Так что не всё столь однозначно. :)
            Так и есть. Содержимое регистров помечается пустым. Это можно изменить в регистре тэгов, чем и "воскресить" хранящиеся там значения, однако смысла в этом нет никакого. FINIT предназначена для начальной инициализации, чтобы сбросить весь предыдущий неизвестный контекст, так что если контекст нужен, проще просто не выполнять инициализацию. У ТС второй FINIT абсолютно лишний.
            При попытке выполнить какою-либо операцию, которая зависит от содержимого регистра, над пустым регистром ведёт к исключению Invalid Operation. После FINIT – да и вообще так в WinAPI принято в качестве дефолтного поведения – все исключения замаскированы, а маскированная реакция на пустой регистр – помещение в него вещественной неопределённости (разновидность NaN). Соответственно любая операция с NaN тоже порождает NaN.
              Цитата Славян @
              Как бы негоже проводить инициализацию на каждый раз. Так, в Винде на 32-битах у меня вообще пишет недопустимую операцию при добавлении числа к пустой ячейке. В 16-битном режиме что-то складывает с давно там записанным. :yes-sad:

              Команда "finit" добавляется в обработку каждой кнопки операции, поскольку неизвестно - с какой операции начнётся работа арифмометра. Я так понимаю - из
              "plus_ex" его лучше убрать ?

              Добавлено
              Цитата Qraizer @
              Так и есть. Содержимое регистров помечается пустым. Это можно изменить в регистре тэгов, чем и "воскресить" хранящиеся там значения, однако смысла в этом нет никакого. FINIT предназначена для начальной инициализации, чтобы сбросить весь предыдущий неизвестный контекст, так что если контекст нужен, проще просто не выполнять инициализацию. У ТС второй FINIT абсолютно лишний.
              При попытке выполнить какою-либо операцию, которая зависит от содержимого регистра, над пустым регистром ведёт к исключению Invalid Operation. После FINIT – да и вообще так в WinAPI принято в качестве дефолтного поведения – все исключения замаскированы, а маскированная реакция на пустой регистр – помещение в него вещественной неопределённости (разновидность NaN). Соответственно любая операция с NaN тоже порождает NaN.

              Т.е. - вообще избавится от "finit" ?
                Так. Смотри. FPU – это устройство, работающее по запросу. Т.е. вот есть команда, оно её выполняет, закончил и есть следующая, выполняет следующую, нет следующей если, останавливается и ждёт новых команд. Он работает параллельно с CPU, асинхронно, поэтому ситуация, когда у него кончились команды, а новых от CPU ещё не поступило – это нормально. При этом в состоянии останова он естественно сохраняет свой контекст неизменным, чтобы как только новая команда, тут же исполнить её на этом контексте. Это не CPU, который не умеет стоять и постоянно должен что-то делать. (На самом деле умеет, но для этого есть специальные команды. Т.е. фактически он даже когда стоит, то не стоит, а выполняет команду "стоять".) Поэтому, когда ты ему даёшь первую команду, FPU может хранить неизвестный тебе контекст от предыдущего потока исполнения. Для этого и нужна FINIT: полностью нейтрализовать влияние предыдущего контекста.
                Но требуется это только в начале работы. Как только ты сделал FINIT, далее ты уже можешь управлять FPU единолично, т.к. он находится под контролем твоей программы. Т.к. ты можешь прогнозировать его состояние, сбрасывать контекст требуется очень редко. Можно сказать, что в подавляющем большинстве случаев и не требуется вовсе. (Если это не так, имеет смысл пересмотреть архитектуру приложения, чем заморачиваться многократными сбросами контекста по ходу её выполнения. Ну и есть ещё особые случаи, типа обработки исключительных ситуаций, чтобы сбросить состояние ошибки и вернуть FPU в нормальный режим.)
                Увы, что-то конкретное посоветовать по твоему коду сложно. Непонятно даже, как ты получаешь числа из полей редактирования, ибо GetWindowText() возвращает в EAX длину текста в поле, переданного в приложение, а не введённое в него значение. И это не говоря уже о SetWindowText() которая работает с текстами, а не числами. По меньшей мере FLDZ не нужна, т.к. FLD и так загружает (теоретически) в вершину стека первый операнд, и не нужен второй FINIT, т.к. он полностью сбрасывает весь предыдущий контекст, и толку было ранее что-либо загружать.
                  Добавлю, что периодическое использование finit маскирует ошибки в программе, что не есть хорошо.
                  Любая нормальная функция должна "убирать за собой". Т.е. внесла 3 числа, 3 же числа с вершины стека и удалила (за исключением случая, когда нужно вернуть значение в регистре st0). Если где-то есть ошибка, finit её прикроет, но от этого она никуда не денется.
                  К тому же, функции могут вызываться друг за другом (хотя это не очень рекомендуется из-за небольшого размера стека FPU), когда результат предыдущей функции будет нужен далее. И finit удалит результат предыдущей функции.

                  Например, ln(x)+sqrt(y):
                  1. Загружаем x [st0=x]
                  2. Вызываем ln, получаем результат [st0=ln(x)]
                  3. Загружаем y [st0=y, st1=ln(x)]
                  4. Вызываем sqrt, получаем результат [st0=sqrt(y), st1=ln(x)] – если в sqrt будет finit, то st1 очистится (пометится как очищенный)
                  5. faddp – складываем x и y (если в sqrt был finit, то ничего не получится... и даже исключение будет замаскировано)
                    Цитата Qraizer @
                    Так. Смотри. FPU – это устройство, работающее по запросу. Т.е. вот есть команда, оно её выполняет, закончил и есть следующая, выполняет следующую, нет следующей если, останавливается и ждёт новых команд. Он работает параллельно с CPU, асинхронно, поэтому ситуация, когда у него кончились команды, а новых от CPU ещё не поступило – это нормально. При этом в состоянии останова он естественно сохраняет свой контекст неизменным, чтобы как только новая команда, тут же исполнить её на этом контексте. Это не CPU, который не умеет стоять и постоянно должен что-то делать. (На самом деле умеет, но для этого есть специальные команды. Т.е. фактически он даже когда стоит, то не стоит, а выполняет команду "стоять".) Поэтому, когда ты ему даёшь первую команду, FPU может хранить неизвестный тебе контекст от предыдущего потока исполнения. Для этого и нужна FINIT: полностью нейтрализовать влияние предыдущего контекста.
                    Но требуется это только в начале работы. Как только ты сделал FINIT, далее ты уже можешь управлять FPU единолично, т.к. он находится под контролем твоей программы. Т.к. ты можешь прогнозировать его состояние, сбрасывать контекст требуется очень редко. Можно сказать, что в подавляющем большинстве случаев и не требуется вовсе. (Если это не так, имеет смысл пересмотреть архитектуру приложения, чем заморачиваться многократными сбросами контекста по ходу её выполнения. Ну и есть ещё особые случаи, типа обработки исключительных ситуаций, чтобы сбросить состояние ошибки и вернуть FPU в нормальный режим.)
                    Увы, что-то конкретное посоветовать по твоему коду сложно. Непонятно даже, как ты получаешь числа из полей редактирования, ибо GetWindowText() возвращает в EAX длину текста в поле, переданного в приложение, а не введённое в него значение. И это не говоря уже о SetWindowText() которая работает с текстами, а не числами. По меньшей мере FLDZ не нужна, т.к. FLD и так загружает (теоретически) в вершину стека первый операнд, и не нужен второй FINIT, т.к. он полностью сбрасывает весь предыдущий контекст, и толку было ранее что-либо загружать.

                    Я скорректировал код в соответствии с рекомендациями:
                    ExpandedWrap disabled
                        ...
                      wmcommand:
                        movzx eax,word ptr [ebp+10h]
                        cmp   eax,..h            ;id_but --> "цифра или символ точка"                
                        je    nabor
                        cmp   eax,1Ch            ;id_but --> "+"                
                        je    plus
                        ...
                        cmp   eax,24h            ;id_but --> "="                
                        je    itog
                        ...
                        jmp   defwndproc
                       
                        ;обработка нажатия кнопок:
                       
                        nabor:
                          ...
                          call  SetWindowTextA@8  ;набрали 1-e число  ;в предыдущем варианте я ошибся с функцией
                          ...
                        plus:                     ;нажали "+"
                          mov   edx,0             ;очищаем регистр и...
                          mov   edx,hbutS         ;...сохраняем id кнопки --> "+"
                          mov   str1,eax          ;сохраняем 1-е число
                          finit                   ;инициируем сопроцессор
                          fld   str1              ;str1-->st(0)
                          call  clear             ;очищаем дисплей  
                          ...
                        ;набрали 2-е число...число набирается и остаётся на дисплее
                          ...
                        itog:                     ;нажали "="
                          cmp   edx,hbutS         ;если нажали "+"...                
                          je    plus_ex           ;...переходим сюда...не переходим
                          ...
                        plus_ex:
                          call  clear             ;очищаем дисплей...очистка не срабатывает
                          mov   str2,eax          ;сохраняем 2-e число в str2
                          mov   eax,buf           ;освобождаем буфер  
                          fadd  str2              ;st(0)+str2-->st(0)
                          fst   buf               ;st(0)-->buf
                          fwait
                          push  buf               ;здесь сумма
                          push  [hWndEdt]
                          call  SetWindowTextA@8  ;выводим её на дисплей
                          jmp   exit
                          ...
                        exit:
                          mov  eax,0
                          jmp  finish
                          ...
                        finish:
                          pop  edi
                          pop  esi
                          pop  ebx
                          pop  ebp
                          ret  16
                      winproc endp
                      clear  proc
                        push  Edt
                        push  [hWndEdt]
                        call  SetWindowTextA@8
                        ret
                      clear  endp
                      end go

                    После нажатия "=" на дисплее остаётся 2-е набранное число. Убрал из "plus_ex:" всё, кроме "call clear" и "jmp exit" - картина не меняется. Похоже, что код в метке "itog:" не работает и переход к "plus_ex:" не происходит. В чём дело - понять не могу. Помогите разобратся.
                    --------------------
                    И ещё один момент: Цифры на дисплее набираются путём нажатия на кнопки арифмометра. В общем случае число - это "string". Число добавляется на дисплей при помощи SetWindowTextA, в результате в ЕАХ остаётся hex-вариант числа (?). И тогда конвертация идёт по цепочке hex-->bin-->hex, или, всё-таки,
                    str-->hex-->bin-->hex-->str ?
                      Цитата cupoma58 @
                      В чём дело - понять не могу. Помогите разобратся.
                      Ну, по приведённым фрагментам ничего сказать нельзя. Что такое hbutS, где лежит в EDX, каковы значения EAX и откуда ни берутся? Ты б полный текст привёл, что ли...

                      Добавлено
                      Второй вопрос тоже непонятен.
                      Цитата cupoma58 @
                      в результате в ЕАХ остаётся hex-вариант числа (?)
                      Если ты, у которого есть полный код, не знаешь, откуда мы-то можем знать?
                        Цитата Qraizer @
                        Ну, по приведённым фрагментам ничего сказать нельзя. Что такое hbutS, где лежит в EDX, каковы значения EAX и откуда ни берутся? Ты б полный текст привёл, что ли...

                        Целиком код очень большой, уже сейчас более 700 строк. Я выбрал код обработки операции "+", он типичный, из "неработающих":
                        ExpandedWrap disabled
                          .386
                          ...
                          WinProc proc
                            push  ebp
                            mov   ebp,esp
                            push  ebx
                            push  esi
                            push  edi
                            ...
                            cmp   dword ptr [ebp+0Ch],WM_COMMAND
                            je    wmcommand
                            ...
                            jmp   defwndproc
                            ...
                            wmcommand:
                              mov   eax,hbut          ;хэндл одной из цифровых кнопок или "."
                              cmp   [ebp+14h],eax     ;нажали цифру или "."  
                              je    nabor             ;переходим сюда
                              ...
                              mov   eax,hbutS         ;хэндл "+"
                              cmp   [ebp+14h],eax     ;нажали "+" ?  
                              je    plus              ;переходим сюда
                              ...
                              mov   eax,hbutI         ;хэндл "="
                              cmp   [ebp+14h],eax     ;нажали "=" ?  
                              je    itog              ;переходим сюда
                              ...
                              mov   eax,hbutC         ;хэндл "С"
                              cmp   [ebp+14h],eax     ;нажали "C" ? (butC db " ",0)  
                              je    clear             ;переходим сюда
                              ...
                              jmp   exit
                              nabor:
                                push  16
                                push  offset buf        ;получаем содержимое буфера (символы)
                                push  [hedt]        
                                call  GetWindowTextA@12
                                add   eax,offset buf    ;добавляем его к тому, что в еах    
                                push  16
                                push  eax               ;туда-же добавляем
                                push  [EBP+14h]         ;символ кнопки
                                call  GetWindowTextA@12
                                push  offset buf        ;набранное число (string или hex - что преобразовывать в bin ?)    
                                push  [hedt]                  
                                call  SetWindowTextA@8
                                ;где-то здесь будет конвертация
                                mov   esi,eax           ;сбрасываем набранные символы в esi: в обработке используем 2 сохранённых регистра - esi и edi  
                                jmp   exit
                              plus:                     ;нажимаем "+"
                                mov   str1,esi          ;сохраняем 1-e число в str1 и...
                                mov   esi,0             ;...очищаем esi
                                mov   edi,hbutS         ;сохраняем хэндл использованной операционной кнопки в edi
                                call  clearproc         ;очищаем дисплей
                                jmp   exit
                              ...
                              clear:
                                call  clearproc
                                jmp   exit
                              ...
                              itog:                     ;набрали 2-е число, НАЖИМАЕМ "=" и смотрим:  
                                cmp   hbutS,edi         ;если разница содержимого = 0 то...                            
                                je    plus_ex           ;...переходим сюда <--- ПЕРЕХОДА НЕ ПОЛУЧАЕТСЯ
                                ...
                                jmp   exit
                                plus_ex:
                                  call  clearproc       ;очищаем дисплей     <---ЕСЛИ ОТАВИТЬ ЭТО    
                                  mov   str2,esi        ;сохраняем 2-е число в str2 и...
                                  mov   esi,0           ;...очищаем esi
                                  mov   edi,0           ;убираем хэндл кнопки из edi
                                  mov   eax,buf         ;освобождаем буфер
                                  finit                 ;инициируем сопроцессор
                                  fld   str1            ;str1-->st(0)
                                  fld   str2            ;str2-->st(0),str1-->st(1)
                                  fadd                  ;str1+str2-->st(0)
                                  fstp  buf             ;st(0)-->buf
                                  ;где-то здесь будет конвертация
                                  push  buf             ;здесь сумма
                                  push  [hedt]          ;выводим её на дисплей
                                  call  SetWindowTextA@8
                                  jmp   exit               <--- И ЭТО - ДИСПЛЕЙ ДОЛЖЕН ОЧИСТИТСЯ - ЭТОГО НЕ ПРОИСХОДИТ
                                ...
                             exit:                      
                               mov   eax,0
                               jmp   finish
                             ...
                             finish:
                              pop   edi
                              pop   esi
                              pop   ebx
                              pop   ebp
                              ret   16
                          winproc endp
                          clearproc proc
                            push  offset Edt
                            push  [hedt]
                            call  SetWindowTextA@8
                            ret
                          clearproc endp
                          end go

                        Возможно, что команды сопроцессора, которыми я пользуюсь, не соответствуют процессору, который у меня стоит (IntelAtom не старше 2006 г.), но из 3-х
                        "прямых" арифметических операций срабатывает только одна - извлечение квадратного корня:
                        ExpandedWrap disabled
                          ...
                          sqr:
                                call  clearproc
                                mov   str1,esi
                                mov   edi,0
                                mov   eax,buf
                                finit
                                fld   str1
                                fsqrt
                                fst   buf
                                fwait
                                push  offset buf
                                push  [hedt]
                                call  SetWindowTextA@8
                                jmp   exit
                          ...

                        возведение в квадрат: не работает - только очистка дисплея
                        ExpandedWrap disabled
                          ...
                           n2:
                              call  clearproc
                              mov   str1,esi
                              mov   edi,0
                              mov   eax,buf
                              finit
                              fld   str1            ;str1-->st(0)
                              fld   str1            ;str1-->st(0),str1-->st(1)
                              fmul                  ;str1*str1-->st(0)
                              fst   buf
                              push  offset buf
                              push  [hedt]
                              call  SetWindowTextA@8
                              jmp   exit
                          ...

                        возведение в куб: не работает - только очистка дисплея
                        ExpandedWrap disabled
                          ...
                          n3:
                              call  clearproc
                              mov   str1,esi
                              mov   edi,0
                              mov   eax,buf
                              finit
                              fld   str1            ;str1-->st(0)  
                              fld   str1            ;str2-->st(0),str1-->st(1)
                              fmul                  ;str1*str1-->st(0)  
                              fld   st(0)           ;копируем st(0)
                              fld   str1
                              fmul                  ;(str1*str1)*str1-->st(0)
                              fst   buf
                              fwait
                              push  offset buf
                              push  [hedt]
                              call  SetWindowTextA@8
                              jmp   exit
                          ...

                        Даже без конвертации что-то должно появлятся.
                          Цитата cupoma58 @
                          Возможно, что команды сопроцессора, которыми я пользуюсь, не соответствуют процессору, который у меня стоит
                          FPU в обед сто лет исполняется. Его архитектура не менялась со времён 80386.
                          Цитата cupoma58 @
                          из 3-х "прямых" арифметических операций срабатывает только одна - извлечение квадратного корня:
                          Похоже, у тебя в коде для FPU две проблемы.
                          Во-первых, я выше говорил, что CPU с FPU работают асинхронно. Это значит, что когда FPU выполняет некую команду, CPU идёт себе спокойно дальше по своим командам, и если FPU требуется некое время для завершения, CPU может уйти уже достаточно далеко. Если тебе в CPU нужны результаты FPU, следует синхронизироваться с ним. Для синхронизации предназначена FWAIT, которая останавливает CPU до того момента, пока FPU не закончит выполнять свою команду. FSQRT у тебя содержит такую синхронизацию, поэтому неудивительно, что она работает, но второй фрагмент наверняка использует результат, который FPU ещё не вычислил и потому не сохранил в памяти. Третий фрагмент сам по себе неправильный, см. ниже.
                          Во-вторых, становится понятно, почему тебе кругом понадобились FINIT. Ты неправильно работаешь со стеком. Ты, похоже, ожидаешь, что после любой команды операнды из стека изымаются, но на самом деле этого не происходит. Например, команда FMUL помещает результат в ST(0), замещая один из сомножителей, но она при этом оставляет в ST(1) второй. Команда FST передаёт вершину стека в приёмник, но при этом она сохраняет неизменным и сам ST(0). Тебе либо следует пользоваться этим, либо нейтрализовывать этот эффект вариантами команд с побочным эффектом на стек, иначе со временем стек весь будет забит ненужными данными, все 8 регистров будут непусты, и поэтому новые FLD будут вызывать исключительные ситуации переполнения стека. FINIT, конечно, всё очищает, поэтому это как бы решение, но я выше говорил, что это плохое решение. Лучше правильно работать со стеком. Например:
                          ExpandedWrap disabled
                            sqr:
                            ; ...
                                  fld   str1
                                  fsqrt
                                  fstp   buf
                                  fwait
                            ...
                            n2:
                            ; ...
                                fld   str1            ;str1-->st(0)
                                fld   str1            ;str1-->st(0),str1-->st(1)
                                fmulp                 ;str1*str1-->st(1) and pop
                                fstp  buf             ;store and pop
                                fwait
                            ...
                             
                            n3:
                            ; ...
                                fld   str1            ;str1-->st(0)  
                                fmul  st(0)           ;str1*str1-->st(0)  
                                fld   str1
                                fmulp                 ;(str1*str1)*str1-->st(1) and pop
                                fstp  buf             ;store and pop
                                fwait
                          Два последних фрагмента можно ещё улучшить, задействуя возможность работы FPU непосредственно с памятью и явными регистрами:
                          ExpandedWrap disabled
                            n2:
                            ; ...
                                fld   str1            ;str1-->st(0)
                                fmul  st(0)           ;str1*str1-->st(0)
                                fstp  buf             ;store and pop
                                fwait
                            ...
                             
                            n3:
                            ; ...
                                fld   str1            ;str1-->st(0)  
                                fmul  st(0)           ;str1*str1-->st(0)  
                                fmul  str1            ;(str1*str1)*str1-->st(0)
                                fstp  buf             ;store and pop
                                fwait
                          но профит будет невелик: сократится код, но он станет менее понятным, и скорость не изменится.

                          Добавлено
                          P.S. И всё ещё непонятно, как ты получаешь данные из текстовых полей и как туда передаёшь результаты. По факту, GetWindowText() и SetWindowText() работают с текстом, но FPU требует чисел. Я не вижу кода, который осуществлял бы преобразования.
                            Цитата Qraizer @
                            Во-первых, я выше говорил, что CPU с FPU работают асинхронно. Это значит, что когда FPU выполняет некую команду, CPU идёт себе спокойно дальше по своим командам, и если FPU требуется некое время для завершения, CPU может уйти уже достаточно далеко. Если тебе в CPU нужны результаты FPU, следует синхронизироваться с ним. Для синхронизации предназначена FWAIT, которая останавливает CPU до того момента, пока FPU не закончит выполнять свою команду.
                            Инструкции CPU и FPU отправляются в один поток исполнения.
                            Такого, чтобы CPU ушёл далеко вперёд, не дождавшись результата работы FPU, нет уже со времён царя Гороха :)

                            Intel:
                            Цитата
                            Because the integer unit and x87 FPU are separate execution units, it is possible for the processor to execute
                            floating-point, integer, and system instructions concurrently. No special programming techniques are required to
                            gain the advantages of concurrent execution. (Floating-point instructions are placed in the instruction stream along
                            with the integer and system instructions.)
                            However, concurrent execution can cause problems for floating-point
                            exception handlers.
                            Инструкции могут исполняться одновременно, но они всё же находятся в едином потоке инструкций, поэтому их логическая последовательность сохраняется, и процессор будет ждать завершения FPU безо всяких fwait'ов (например, в последовательности fstp [X] + mov eax,[X] инструкция mov eax,[X] будет выполнена только после завершения fstp [X]). Единственное, что может быть – это перестановка инструкций, результаты которых не влияют друг на друга, но это уже другая тема, не связанная непосредственно с FPU.

                            Инструкция fwait (wait) уже давно используется только для синхронизации исключений.

                            Так что в этом проблемы быть точно не может.

                            Добавлено
                            Можно даже провести маленький эксперимент (без чтения мануалов):
                            ExpandedWrap disabled
                              fld1
                              rdtsc
                              mov ecx,eax
                              fsin
                              rdtsc
                              sub eax,ecx
                              fstp st
                            Запускаем, получаем в EAX значение 129-132 (пишу то, что выходит у меня).
                            Заменяем fsin на fadd st,st (менее ресурсоёмкое вычисление), получаем 21-36.
                            Убираем обе, получаем почти то же, что и с fadd (но чаще 21, чем 36).
                            Если бы CPU просто посылал FPU "задание" для исполнения, результат был бы одинаковым (или почти одинаковым).
                              Цитата Qraizer @
                              ]Похоже, у тебя в коде для FPU две проблемы.
                              Во-первых...
                              P.S. И всё ещё непонятно, как ты получаешь данные из текстовых полей и как туда передаёшь результаты. По факту, GetWindowText() и SetWindowText() работают с текстом, но FPU требует чисел. Я не вижу кода, который осуществлял бы преобразования.

                              Благодарю за советы. Заменю fst на fstp. Что касается "текст-число-текст" - эти процедуры ещё в процессе. Finit я использую в каждой операции потому, что неизвестно - с какой начнётся работа. И мне, всё-таки, непонятно: почему не происходит перехода в цепочке plus-itog-plus_ex ? В Java, при ветвлении, используется сравнение с типом арифметического действия (+,-...). Я сохраняю хэндл кнопки в edi (plus) и в itog проверяю - какая кнопка была нажата "cmp
                              hbut,edi". Почему не работает ?
                                Цитата cupoma58 @
                                Цитата Qraizer @
                                ]Похоже, у тебя в коде для FPU две проблемы.
                                Во-первых...
                                P.S. И всё ещё непонятно, как ты получаешь данные из текстовых полей и как туда передаёшь результаты. По факту, GetWindowText() и SetWindowText() работают с текстом, но FPU требует чисел. Я не вижу кода, который осуществлял бы преобразования.

                                Благодарю за советы. Заменю fst на fstp. Что касается "текст-число-текст" - эти процедуры ещё в процессе. Finit я использую в каждой операции потому, что неизвестно - с какой начнётся работа. И мне, всё-таки, непонятно: почему не происходит перехода в цепочке plus-itog-plus_ex ? В Java, при ветвлении, используется сравнение с типом арифметического действия (+,-...). Я сохраняю хэндл кнопки в edi (plus) и в itog проверяю - какая кнопка была нажата "cmp
                                hbut,edi". Почему не работает ?

                                Всё - разобрался. В цепочке "oper-->itog-->oper_ex" были лишние команды. Теперь по сопроцессору: мой компилятор (masm32v11) обозвал команду fmulp - инвалидной и сказал, что st(0) не может быть первым операндом (fmul st(0)). Не работает самый простой код:
                                ExpandedWrap disabled
                                  ...          ;   st    st(1)   st(2)  ...  st(7)
                                  finit        ;   -      -       -           -
                                  fld  str1    ;  str1    -       -           -
                                  fld  str1    ;  str1   str1     -           -
                                  fmul         ;  itog    -       -           -
                                  fstp         ;   -      -       -           -
                                  fwait
                                  ...

                                Предложенные варианты кода - так-же не работают. Всё заработало, а возведение в квадрат и в куб - не хочет ! Причём, не работает арифметический код,
                                предварительная очистка дисплея - происходит. Если, только, это очистка. Что посоветуете ?
                                  fmulp без операндов – вполне себе нормальная инструкция (фактически это fmulp st(1),st).
                                  fmul без операндов превращается в fmulp (если компилятор не ругается), а вот fmul st(x) действительно инвалидная тема, т.к. одного операнда недостаточно, нужно писать fmul st(x),st (для fmulp тоже) или fmul st,st(x) (для fmulp второй операнд не может быть не st).
                                  Поэтому fstp тут у вас вообще бесполезная инструкция, т.к. она фактически удаляет st(1), который пуст после fmul (а фактически fmulp).

                                  Если нужно возвести в квадрат, делайте так:
                                  ExpandedWrap disabled
                                    fld str1
                                    fmul st,st  ; результат в st(0)

                                  В куб:
                                  ExpandedWrap disabled
                                    fld str1
                                    fld st
                                    fmul st,st
                                    fmulp  ; результат в st(0)


                                  Добавлено
                                  p.s. st то же самое, что и st(0), если что ;)
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0606 ]   [ 16 queries used ]   [ Generated: 28.03.24, 13:07 GMT ]