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

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

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

Так что добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: 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?
user posted image Чат форума в Telegramuser posted image Чат форума в Discord (жми и подключайся!) ;)
Цитата 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, то ничего не получится... и даже исключение будет замаскировано)
user posted image Чат форума в Telegramuser posted image Чат форума в Discord (жми и подключайся!) ;)
Цитата 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 "задание" для исполнения, результат был бы одинаковым (или почти одинаковым).
user posted image Чат форума в Telegramuser posted image Чат форума в Discord (жми и подключайся!) ;)
Цитата Qraizer @
]Похоже, у тебя в коде для FPU две проблемы.
Во-первых...
P.S. И всё ещё непонятно, как ты получаешь данные из текстовых полей и как туда передаёшь результаты. По факту, GetWindowText() и SetWindowText() работают с текстом, но FPU требует чисел. Я не вижу кода, который осуществлял бы преобразования.

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


Рейтинг@Mail.ru
[ Script Execution time: 0,1811 ]   [ 19 queries used ]   [ Generated: 23.05.18, 22:22 GMT ]