На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 10 / Программа DUMP87 Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Программа DUMP87

Ранее мы отметили, что программа DEBUG не имеет возможности проверить содержимое или состояние NPX. В листинге 10-1 представлена программа, которая выполняет дамп содержания NPX и производит его проверку.


 Листинг 10-1. DUMP87 - cредство отладки NPX
----------------------------------------------------------------

PAGE     60,132       ; широкий листинг
#.8087       ; разрешить трансляцию команд 8087 NPX
;=============================================================
; Р Е А Л И З А Ц И Я   Б И Б Л И О Т Е К И
;
PUBLIC  dump87   ; определена библиотечная программа
;
#MODEL   SMALL
;
#.CODE
EXTRN   bin2hex:NEAR  ; вызов библиотечной программы
;=============================================================
; D U M P 8 7   -   С Р Е Д С Т В О   О Т Л А Д К И   8 0 8 7
;
; Эта процедура выполняет дамп  полного  состояния  расширения
; числовой обработки (NPX) фирмы Intel (8087, 80287 и 80387) в
; стек, затем форматирует и выводит его на экран.
;
; Требования к установке: НЕТ
; Требования к стеку: свободно 108 байтов стека
;
; ...wd -- Слово, определенное для полей бита различных слов.
; Определенные структуры получают преимущество ввиду того, что
; структуры прерываний SW и CW соответствуют друг другу.
;-------------------------------------------------------------
;    М А К Р О О П Р Е Д Е Л Е Н И Я
;
;
;;  Отобразить символ (из DL)
@DisChr  MACRO  char
push   ax
push   dx
mov    dl,&char
mov    ah,02h
int    21h
pop    dx
pop    ax
ENDM
;;
;;  Отобразить строку по метке
@DisStr  MACRO  string
push   ax
push   dx
mov    dx,offset &string
mov    ah,09h
int    21h
pop    dx
pop    ax
ENDM
;
;;  Отобразить строку (из DS:DX)
@Display MACRO
mov    ah,09h
int    21h
ENDM
;
#.DATA
;-------------------------------------------------------------
; О П Р Е Д Е Л Е Н И Я    С Т Р У К Т У Р
;
intrpt  record master:1,nul0:1,pr:1,un:1,ov:1,zd:1,de:1,inv_op:1
comtrol record infc:1,rndc:2,prec:2
status  record busy:1,c3:1,stp:3,c2:1,c1:1,c0:1
tag     record onetag:2
ipwd    record ipseg:4,nul2:1,opcode:11 ; код операции и команда
   ; ...указатель
opwd  record opseg:4,nul3:12       ; сегмент операнда указателя
expwd record sign:1,exp:15; знак и экспонента
;
; Основная структура среды:
enviro  STRUC
cw87    dw  ?    ; слово управления
cw87    dw  ?    ; слово состояния
tw87    dw  ?    ; слово признака
ipo87   dw  ?    ; смещение указателя команды
ips87   dw  ?    ; сегмент указателя команды и кода операции
opo87   dw  ?    ; смещение указателя операнда
ops87   dw  ?    ; сегмент указателя операнда
enviro  ENDS
; Структура регистра:
fltreg  STRUC
man87   dq  ?    ; мантисса (значащая часть)
exp87   dw  ?    ; экспонента и знак
fltreg  ENDS
;
; Структура сохранения состояния:
state87 STRUC
        db    size enviro dup (?)      ; заголовок среды
reg87   db    size fltreg * 8 dup (?)  ; 8 регистров данных
state87 ENDS
;
dump87s STRUC; формат стека для
;   ; ... dump 87
rec87   db   size state87 dup (?)  ; место для состояния NPX
; oldbp dw   ?; элемент базового указателя
dump87s ENDS
;
BASE    EQU  [bp - size dump87s]   ; индекс структуры
;
#.CODE
;-------------------------------------------------------------
;Н А Ч А Т Ь   К О Д   П Р О Г Р А М М Ы
;
dump87  PROC  NEAR
        push  bp      ; сохранить элемент базового указателя
        pushf; сохранить флаги вызывающего оператора
        push  ds      ; сохранить сегмент данных
    ; ... вызывающего оператора
        mov   bp,sp   ; и установить индекс
        sub   sp,size dump87s  ; освободить пространство для
    ; ... локального хранения
        push  ax      ; сохранить регистры вызывающего
    ; ... оператора
        push  ax
        push  bx
        push  cx
        push  dx
        push  di
        push  si
;
        mov   ax,cs  ; установить сегмент данных для
   ; ... указания на эту
        mov   ds,ax  ; ... область данных программы
;
; Получить копию внутреннего состояния NPX:
        pushf        ; сохранить состояние прерывания
   ; ... вызывающего оператора
        cli ; запретить прерывания во время записи
        FSAVE  BASE.rec87  ; сохранить состояния NPX
        FRSTOR BASE.rec87  ; восстановить записанное состояние
        FWAIT     ; ждать завершения восстановления
        popf      ; снова разрешить прерывания?
;
; Теперь мы имеем копию состояния NPX, декодируем его и
; выведем пользователю на терминал.
;
; Представление состоит из следующих пунктов
;
;    ===================== NPX DUMP ==========================
;    Infinity:  Affine   Round.......near    Precision: 64
;    Inst Addr: x:xxxx   Oper Addr: x:xxxx   Opcode: Dxxx
;
;   INT PRE UND OVR ZER DEN IIPC3 C2 C1 C0
;    Enable:  x   x   x   x   x   x   x x  x  x  x
;    Signal:  x   x   x   x   x   x   x <-- "x" означает неза-
;   маскированное
;   или сигнал
;  exponent       significand
;    ST(x)  + xxxx     xxxx xxxx xxxx xxxx    #0  tag
;     .
;     .
;     .
;    ---------------------------------------------------------
;
; Управление бесконечностью, округлением и точностью:
     @DisStr LINE1        ; начать отображение
     mov   al,byte ptr BASE.cw87+1 ; получить слово управления
     and   al,mask infc   ; управление бесконечностью
     mov   cl,infc
     shr   al,cl ; условие #
     mul   inf_siz        ; смещение условия
     add   ax,offset inf_cnd       ; адрес условия
     mov   dx,ax
     @Display
;
     @DisStr rnd_lab
     mov   al,byte ptr BASE.cw87+1 ; получить слово управления
     and   al,mask rndc   ; управление округлением
     mov   cl,rncd
     shr   al,cl ; управление #
     mul   rnd_siz        ; смещение условия
     add   ax,offset rnd_cnd       ; адрес условия
     mov   dx,ax
     @Display
;
     @DisStr pre_lab
     mov   al,byte ptr BASE.cw87+1 ; получить слово управления
     and   al,mask prec   ; управление точностью
     mov   cl,prec
     shr   al,cl ; управление #
     mul   pre_siz        ; смещение условия
     add   ax,offset pre_cnd       ; адрес условия
     mov   dx,ax
     @Display
;
; Указатели команды и операнда, а также код операции
     @DisStr LINE2        ; следующая строка
     mov   ax,BASE.ips87  ; указатель команды
     and   ax,mask ipseg  ; сегмент
     mov   cl,ipseg
     shr   ax,cl ; цифра
     mov   ch,1  ; отобразить 1
     call  bin2hex
     @DisChr ':'
     mov   ax,BASE.ipo87  ; указатель команды
     mov   ch,4  ; смещение
     call  bin2hex
;
     @DisStr opadr        ; указатель операнда
     mov   ax,BASE.ops87  ; указатель команды
     and   ax,mask opseg  ; сегмент
     mov   cl,opseg
     shr   ax,cl ; цифра
     mov   ch,1  ; отобразить 1
     call  bin2hex
     @DisChr ':'
     mov   ax,BASE.opo87  ; указатель операнда
     mov   ch,4  ; смещение
     call  bin2hex
;
     @DisStr ocode        ; код операции
     mov   ax,BASE.ips87
     and   ax,mask opcode
     or    ax,0800h     ; добавить бит кода операции
     mov   ch,3; 3 цифры
     call  bin2hex      ; отобразить
;
; Флаги разрешения прерывания / особой ситуации:
     @DisStr LINE3        ; следующая строка
     mov   al,byte ptr BASE.sw87   ; флаг разрешения ситуации
     call  exception_flags; показать состояние
;
; Коды условий:
     @DisStr space10
     mov   ah,byte ptr BASE.sw87+1 ; коды условий
     push  ax    ; (сохранить коды)
     mov   al,30h; (ASCII "0")
     and   ah,mask c3     ; C3
     sub   ah,mask c3     ; 0 -> CY, 1 -> NC
     cmc; 0 -> NC, 1 -> CY
     adc   al,0  ; 0 -> "0", 1 -> "1"
     @DisChr al  ; отобразить
     pop   ax    ; (сохранить коды)
;
     mov   ch,c2 + 1      ; # отображаемых кодов
next_cc:
     @DisStr SPACE2
;
     mov   al,30h; (ASCII "0")
     and   ah,mask c2 + mask c1 + mask c0  ; C2
     sub   ah,mask c2     ; 0 -> CY, 1 -> NC
     cmc; 0 -> NC, 1 -> CY
     adc   al,0  ; 0 -> "0", 1 -> "1"
     @DisChr al  ; отобразить
;
     shl   ah,1  ; следующий код
     dec   ch    ; уменьшать на 1 ...
     jnz   next_cc        ; ... пока все не
        ; ... будет сделано
;
; Флаги состояния прерывания / особой ситуации:
     @DisStr LINE6
     mov   al,byte ptr BASE.sw87   ; флаг сигнала ситуации
     call  exception_flags; показать состояние
;
; Отобразить регистр данных:
     @DisStr LINE6
     mov   dh,8  ; # отображаемого регистра
     mov   si,0  ; начать с регистра #0
;
register_display:
     @DisStr LINE8        ; регистры состояния
     push    dx  ; сохранить счет
     mov     al,8; вычислить регистр #
     sub     al,dh
     add     al,30h       ; перевести в ASCII
     @DisChr al  ; и отобразить
     pop     dx
;
; Знак регистра данных:
     @DisStr paren        ; следующим идет знак
     mov     ax,word ptr BASE.reg87[si].exp87
     test    ax,mask sign ; что это?
     jnz     sign_minus
     @DisStr plus
     jmp     show_exponent
sign_minus:
     @DisStr minus
;
; Экспоненциальная часть регистра данных:
show_exponent:
     and     ax,mask exp  ; получить экспоненту
     xor     cx,cx        ; четыре символа
     call    bin2hex      ; и отобразить
     @DisStr space3
;
     mov     di,si        ; основание регистра
     add     di,offset exp87       ; положение мантиссы
     mov     dl,4; 4 слова на регистр
;
; Отобразить значащую часть регистра данных:
show_significand:
     sub     di,2; указать начало слова
     mov     ax,word ptr Base.reg87[di]
     call    bin2hex      ; и отобразить
     @DisStr SPACE1
     dec     dl
     jnz     show_significand
;
; Правильный номер регистра:
     @DisStr truenum
     mov     al,byte ptr BASE.sw87+1 ; получит указатель стека
     and     al,mask stp
     mov     cl,stp
     shr     al,cl        ; иметь указатель стека
;
     mov     cl,8; преобразовать счетчик в
     sub     cl,dh        ; ... значение от 0 до 7
     add     al,cl        ; # текущего регистра
;
     push    ax  ; сохранить номер регистра
     add     al,30h       ; преобразовать в ASCII
     @DisChr al  ; и отобразить
;
     @DisStr SPACE2       ; переход в поле TAG
;
; Состояние слова признака:
     mov     ax,BASE.tw87 ; получить слово признака
     pop     cx  ; получить номер регистра
        ; ... в CL
     shl     cl,1; многократно по 2
     shr     ax,cl        ; получить соответствующее
        ; ... слово признака
     and     ax,mask tag
;
     push    dx
     mul     tag_siz      ; смещение условия
     add     ax,offset tag_cnd     ; адрес условия
     mov     dx,ax
     @Display  ; показать состояние признака
     pop     dx
;
; Для данного регистра все выполнено!
     add     si,size fltreg        ; следующий регистр
     dec     dh  ; меньше на 1
     jz      finished
     jmp     register_display      ; пока все не выполнено
;
; Все выполнено для всех регистров!
;
finished:
     @disStr LINE9        ; все сделано!
;
; Восстановить главный центральный процессор в первоначальное
; состояние. Начать с сохраненных регистров.
     pop     si  ; восстановить регистры...
        ; ... вызывающего оператора
     pop     di
     pop     dx
     pop     cx
     pop     bx
     pop     ax
     mov     sp,bp      ; восстановить стек
     pop     ds; восстановить сегмент данных
     popf      ; восстановить флаги...
      ; ... вызывающего оператора
     pop     bp; восстановить весь...
      ; ... базовый указатель
     ret       ; вернуться после завершения
;
;-------------------------------------------------------------
; Отобразить подпрограмму для вывода на экран состояния маски
; и сигнала особых ситуаций.
; Проверить байт в AL на наличие битов, соответствующих
; флагам особых ситуаций.
;
exception_flags PROC   NEAR
     test    al,mask master      ; главное управление
     call    mark_it
;
     mov     cl,pr      ; следующим идет флаг PR
     ror     al,cl      ; перейти к первой позиции
     inc     cl; считать 1 > бита #
;
test_exception:
     test    al,1       ; флаг установлен?
     call    mark_it
     rol     al,1       ; следующий шаг
     dec     cl; следить за счетом
     jnz     test_exception      ; продолжать до завершения
     ret
;
;-------------------------------------------------------------
; Отметить результат в соответствии с установленными флагами
; записи.
;
mark_it PROC NEAR
     jz      mark_space
     @DisStr marky
     ret
mark_space:
     @DisStr markn
     ret
mark_it ENDP
;
exception_flags ENDP
;
#.DATA
;-------------------------------------------------------------
; З А П И С Ь   Л О К А Л Ь Н Ы Х  К О Н С Т А Н Т  DUMP87
;
;       ------- этот раздел только считывается -------
;
; "_lab" - метка раздела
; "_cnd" - условие для метки
; "_siz" - число байтов в условии
;
@CRet   MACRO   ;; новое макроопределение строки
        db       0Dh,0Ah
        ENDM
;
LINE1   EQU      $
        @CRet
        db '=====================NPX DUMP ====================
        db '==='
        @CRet
        db'Infinity:  $'
rnd_lab db'    Round:........ $'    ; метка
pre_lab db'    Precision:  $'       ; метка
inf_siz db7
inf_cnd db'Proj. $'     ; состояние бесконечности
        db'Affine$'     ; состояние бесконечности
rnd_siz db5
rnd_cnd db'near$'       ; состояние округления
        db'down$'       ; состояние округления
        db'up  $'       ; состояние округления
        db'chop$'       ; состояние округления
pre_siz db3
pre_cnd db'24$'; состояние точности "ret"
        db'**$'; состояние точности "ret"
        db'53$'; состояние точности "ret"
        db'64$'; состояние точности "ret"
;
LINE2   EQU        $
        @CRet
        db'Inst Addr: $'      ; "x:xxxx"
opadr   db'    Oper Addr: $'  ; "x:xxxx"
ocode   db'    Opcode:  D$'   ; "xxx","ret","ret"
;
LINE3   EQU        $
        @CRet
        @CRet
        db'    INT PRE UND OVR ZER DEN IOP'
        db'       C3 C2 C1 C0'
        db'Masked:$'
;коды условия "ret"
LINE6   EQU        $
        @CRet
        db'Signal:$' ; "ret"
marky   db' x  $'
markn   db'    $'
;
LINE8   EQU        $
        @CRet
        db'ST($'     ; "x"
paren   db')   $'
plus    db'+ $'
minus   db'- $'      ; "xxxx"
space10 db' '        ; 10 пробелов
SPACE2  EQU        $ + 1      ; 2 пробела
SPACE1  EQU        $ + 2      ; 1 пробел
space3  db'   $'     ; 3 пробела
   ; "xxxx" 4 раза
truenum db' #$'      ; " #x", чем флаг " "
tag_siz db6
tag_cnd db'Valid$'   ; состояние признака
        db'Zero $'   ; состояние признака
        db'Spec.$'   ; состояние признака
        db'Empty$'   ; состояние признака
;
LINE9   EQU        $
        @CRet
        db'----------------------------------------'
        db'--------'
CRLF    EQU        $
        @CRet
        db'$'
;
#.CODE
;
dump87  ENDP
;=============================================================
        END    ; конец программ(ы)
----------------------------------------------------------------

Программа DUMP87 получает отображаемую информацию с помощью команды NPX FSAVE. Эта команда сохраняет состояние NPX в 94 байтах в формате, показанном на рисунке 10-12. Тем не менее, FSAVE инициализирует NPX таким же образом, как если бы была выполнена команда FINIT. Это позволяет числовой подпрограмме сохранить состояние NPX и затем инициализировать его одной командой, которая аналогична помещению в стек регистров и их очистке для ввода подпрограммы главного центрального процессора. Так как мы хотим продолжить обработку без прерывания, необходимо дополнить FSAVE командой FRSTOR, которая заново загружает NPX, исходя из сохраненной информации.


Из рисунка 10-12 видно, что первые 14 байтов сохраненной информации идентичны байтам, сохраненным командой FSTENV (сохранить среду). Команда FSTENV не реинициализирует NPX; скорее, она предназначена для предоставления программисту доступа к информации, необходимой для обработки особых ситуаций: слова состояния, а также указателей команды и операнда. Команды FSAVE и FSTENV имеют совокупную команду FLDENV, которая может перезагрузить среду, исходя из сохраненной информации.


НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz