ZXNet эхоконференция «code.zx»


тема: ГЛЮК ПРОЦЕССОРА (2/2)



от: Kirill Frolov
кому: All
дата: 27 Nov 1998
Hi, All !

Продолжение сабжа:

===============================================================================
=

7. Окончательное подтверждение
──────────────────────────────

Проверим этот факт. Пусть обработчик прерывания определяет,
в каком месте была прервана программа. Если она была прервана
именно после команды LD A,R, пусть бордюр на некоторое время
станет желтым:

ORG #6000

LD HL,#8000
LD (HL),#81
LD DE,#8001
LD BC,#100
LDIR
LD A,#80
LD I,A
IM 2

EI

M1 CALL SUBR1
JR M1

SUBR1 LD A,R
BP1 RET PE

LD A,4
OUT (254),A
LD HL,0
LD DE,0
LD BC,#600
LDIR ;WAIT
XOR A
OUT (254),A
RET


ORG #8181

EXX
EX AF,AF'

POP HL
PUSH HL
LD DE,BP1
AND A
SBC HL,DE
JR NZ,NE_BP1

LD A,6
OUT (254),A
LD HL,0
LD DE,0
LD BC,#600
LDIR ;WAIT

NE_BP1 EXX
EX AF,AF'

EI
RET

Если неправильная работа команды LD A,R не связана с тем,
что во время ее выполнения приходит импульс прерывания, то мы
увидим, как верхняя часть border'а будет мигать то зеленым цве-
том, то желтым. Hо если связь между этими двумя событиями су-
ществует, то мы должны увидеть, как верхняя часть border'а мига-
ет желтым цветом, а нижняя часть - зеленым, причем они должны
мигать совершенно синхронно.

Запускаю - и вижу именно то, что и предполагал. Действи-
тельно, такая связь существует:

┌─────────────────────────────────┐
│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│
│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│
│▓▓▓▓ ▓▓▓▓│
│▓▓▓▓ ▓▓▓▓│
│▒▒▒▒ ▒▒▒▒│
│▒▒▒▒ ▒▒▒▒│
│▒▒▒▒ ▒▒▒▒│
│▒▒▒▒ ▒▒▒▒│
│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│
│ │
└─────────────────────────────────┘

Hо как могут быть связаны прерывания и работа команды LD
A,R? Эта команда помещает во флаг P/V содержимое триггера преры-
ваний IFF2. При разрешенных прерываниях этот триггер равен 1, а
когда приходит импульс прерывания, он автоматически сбрасы- ва-
ется в 0, чтобы исключить повторную обработку прерывания. Hо об-
работка запроса на прерывание начинается во время выполнения
последнего такта выполняемой команды (т.е. команды LD A,R). И,
видимо, уже сброшенный триггер IFF2 копируется во флаг P/V
(действительно, с точки зрения процессора, прерывания в этот мо-
мент уже запрещены).

Все сказанное относится и к команде LD A,I. Приведенная ин-
формация была проверена на оригинальном процессоре Z80 фирмы ZI-
LOG и на отечественном аналоге КP1858ВМ1.


8. К чему это приводит и что делать?
────────────────────────────────────

Применение команд LD A,R и LD A,I для определения состояния
триггера прерываний, вообще говоря, используется во многих про-
граммах (и даже в ПЗУ TR-DOS). Вот вам и объяснение некоторого
числа странных зависаний. Кажется, будто вероятность прихода им-
пульса прерывания именно во время выполнения команды LD A,R не-
велика. Hо, во-первых, вероятность увеличивается за счет того,
что эта команда может выполняться в программе не один раз (а для
зависания достаточно единственного неверного выполнения), и,
вовторых - если в программе до этого встречалась команда HALT,
т.е. синхронизация с прерываниями, может случиться так, что ко-
манда LD A,R будет каждый раз выполняться в то время, когда наи-
более вероятно очередное прерывание (так и было в BestView).

Итак, этот способ ненадежен. Hо как же быть? Оказывается,
можно со 100% точностью определять состояние триггера прерываний
по следующему простому правилу:

- выполнить команду LD A,R;
- если флаг P/V = 1 - значит, прерывания в самом деле
разрешены;
- если флаг P/V = 0 - либо прерывания в самом деле запрещены,
либо они разрешены, но команда LD A,R неверно установила
флаг. Чтобы устранить неопределенность, еще раз выполняем
команду LD A,R. Если и теперь флаг P/V = 0 - значит,
прерывания запрещены (в самом деле, не может быть так,
чтобы и во время выполнения второй команды LD A,R произошло
прерывание - между двумя прерываниями проходит 1/50 секунды,
а между двумя командами LD A,R - гораздо меньше времени).
Если же флаг P/V = 1 - значит, прерывания разрешены.

Вот соответствующий фрагмент программы:

SUBR1 LD A,R
JP PE,M1
LD A,R
M1 PUSH AF
DI

....

POP AF
DI
RET PO
EI
RET


9. Как это можно использовать?
──────────────────────────────

С помощью команды LD A,R удобно выполнять тестирование про-
цессора, чтобы распознать выполнение программы под эмулятором.
Эмулятор выполняет команды Z80 последовательно, одну за другой,
и команда LD A,R всегда будет правильно устанавливать флаг P/V.
А в реальном Z80 это не так.

Вот простейшая процедура для тестирования процессора, кото-
рая возвращает в аккумуляторе 1, если она запущена на реальном
Z80, и 0 в противном случае. Она пытается 65536 раз прочитать
регистр R при разрешенных прерываниях, и если при этом хотя бы
один раз флаг P/V установится в 0 - делается вывод, что процеду-
ра работает на реальном Z80.

TESTZ80 EI
LD BC,0
M1 LD A,R
JP PO,QUIT
INC BC
LD A,B
OR C
JR NZ,M1
RET
QUIT LD A,1
RET

Если распознался эмулятор, можно либо прекращать выполне-
ние программы (своеобразная защита), либо отключать некоторые
участки программы, которые могут неверно работать под эмулятором
(например, вместо прямой работы с ВГ93 использовать точку входа
#3D13 и т.п.).


10. Исправление STS 6.2
───────────────────────

В известном отладчике STS определение состояния триггера
прерываний также происходит с помощью команды LD A,R. Из-за это-
го может неправильно выполняться трассировка программы. При
трассировке STS запускает каждую команду (кроме команд передачи
управления) с помощью резидента, а после окончания ее выполнения
запоминает содержимое регистров процессора и состояние триггера
прерываний. Вот тут и возможны ошибки.

Допустим, прерывания разрешены и трассируется такая простей-
шая программа:

#8000 NOP
#8001 JR #8000

Прекратив трассировку через некоторое время (при отключенной
опции Indicate одной минуты вполне достаточно), мы увидим, что
прерывания оказались запрещены. Если бы трассировалась реальная
программа, такое запрещение прерываний могло оказать влияние на
весь ход ее дальнейшего выполнения и даже привести к зависанию
(если при трассировке попалась бы команда HALT).

Совершенно очевидно, что в STS надо внести исправления. Вот
как это сделать для версии 6.2:

Сначала нужно запустить STS и загрузить файл "sts6.2
", в котором и будут производиться исправления.

Затем нужно отыскать свободные 14 байт - их назначение будет
объяснено ниже. Можно использовать буфер функции пользователя (с
адреса #FE37). Hо в той версии STS, которую я использую, этот
буфер занят под процедуру дизассемблирования с метками ассембле-
ра ZX ASM, поэтому я решил сократить некоторые текстовые сообще-
ния:

'Block' -> 'Bl.' (экономится 2 байта)
'Save' -> 'S.' (----/----- 2 --/--)
'Load' -> 'L.' (----/----- 2 --/--)
' DEFB' -> ' ' (----/----- 4 --/--)
'FileName' -> 'Name' (----/----- 4 --/--)

Для этого с адреса #EB24 нужно ввести следующую последова-
тельность байт:

#EB24: AE 46 72 6F ED 54 EF 46
#EB2C: 69 6C E5 53 65 63 74 6F
#EB34: F2 53 AE 4C AE 53 74 6F
#EB3C: 70 20 69 E6 42 61 6E EB
#EB44: 51 75 69 F4 54 72 61 63
#EB4C: E5 53 74 61 72 F4 44 69
#EB54: 73 61 73 ED A0 46 69 6C
#EB5C: E5 42 41 53 49 C3 20 44
#EB64: 4F D3

По адресу #E702 заменяем значение #0A на #0E, чтобы правиль-
но печаталось имя файла (т.к. вместо строки FileName осталось
просто Name).

Итак, теперь с адреса #EB66 свободно 14 байт. Смотрим, где в
STS происходит определение состояния триггера прерываний:

#DFFE: LD (#5BA1),SP
LD SP,#5BA1
PUSH BC
PUSH AF
LD A,R
DI
LD BC,#7FFD
LD A,#1F
OUT (C),A
LD B,#BF
LD A,#00
OUT (C),A
JP #E028

Заменим команды LD A,R: DI на NOP, а команду JP #E028 - на
JP #EB66. С адреса #EB66 поместим такой фрагмент:

#EB66: LD A,R
JP PO,#EB6E ┐
NOP │
┌─ JR #EB70 │
│ LD A,R <───┘
└> DI
JP #E028

Обратите внимание - этот фрагмент в любом случае при своей
работе увеличивает регистр R на одинаковую величину (на 7). Дело
в том, что далее будет выполнена еще одна команда LD A,R, на
этот раз нужная уже для определения значения регистра R, и будет
произведена коррекция полученного значения, т.к. значение ре-
гистра R увеличивается с каждой выполненной командой, а надо уз-
нать его значение на момент окончания выполнения трассируемой
команды. Вот как это выглядит:

#DCA2: LD A,#5A
LD HL,#FEF4
SLA (HL)
RLA
ADD A,(HL)
RRCA
LD (HL),A
RET

Константу #5A по адресу #DCA3 следует заменить на #53, т.е.
уменьшить на 7 - ведь в программу был добавлен дополнительный
фрагмент, увеличивающий регистр R на 7, и надо скомпенсировать
это изменение.

После этого остается только записать измененный файл на
диск.

* * *
===============================================================================
=
THE END


With best wishes, Kirill Frolov.




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Штурм - "Подсказки из подземелья" заинтересуют многих поклонников игры "Bards Tale".
Обзор новинок - Правила Дорожного Движения (demo), Gift for Diver.
Список BBS - Сетевые новости.
Всякая всячина - Почтовый ящик.
Реклама - Пpодам, куплю ,обменяю пpогpаммы для ZX Spectrum.

В этот день...   25 апреля