Листинг 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 ; конец программ(ы)
----------------------------------------------------------------
|