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


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



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

Взято из ZX.SPECTRUM:

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

(c) Иван Pощин, Москва, 13.11.1998

Fido : 2:5020/689.53
E-mail: asder_ffc@softhome.net

┌─────────────────────────────────┐
│ │
│ Hедокументированная особенность │
│ процессора Z80 │
│ │
└─────────────────────────────────┘

Pазрешается свободное распространение этой статьи при усло-
вии не внесения каких-либо изменений и сохранения моего копирай-
та.


1. С чего все началось
──────────────────────

Писал я как-то очередную версию программы BestView (v2.4), и
использовал в ней вот такой фрагмент:

....
EI
CALL SUBR1
HALT
....


SUBR1 LD A,R
PUSH AF
DI

....

POP AF
DI
RET PO
EI
RET

В этом фрагменте происходит вызов процедуры SUBR1, которая
на время своей работы запрещает прерывания, а при выходе восста-
навливает прежний режим их работы.

Проверка того, разрешены или запрещены прерывания при вызове
процедуры, и восстановление режима прерываний происходит следую-
щим образом:

- команда LD A,R заносит во флаг P/V состояние триггера
прерываний IFF2;
- регистровая пара AF запоминается в стеке (PUSH AF);
- запрещаются прерывания (DI);
- выполняются, собственно, те функции, для которых и
предназначалась процедура SUBR1;
- содержимое AF восстанавливается (POP AF);
- прерывания запрещаются (DI);
- если флаг P/V сброшен, происходит выход из процедуры с
запрещенными прерываниями (RET PO);
- иначе происходит выход с разрешенными прерываниями (EI:
RET).

Я стал замечать, что при работе этого фрагмента BestView за-
висает - не всегда, и даже не слишком часто, а в очень редких
случаях. Hо все равно это было не очень-то приятно. Программа,
вроде бы, не содержала никаких ошибок, по крайней мере с первого
взгляда ничего подозрительного я не заметил. Оставалось лишь
прибегнуть к более сильным средствам...


2. Ситуация начинает проясняться
────────────────────────────────

После очередного зависания я вставил чистый диск и уверенно
нажал кнопку MAGIC. Затем загрузил отладчик "STS 6.2 +@" (не зря
я его переделывал - теперь с его помощью после загрузки @-файла
можно восстановить содержимое регистров процессора на момент
сброса программы на диск). Hажатие пары клавиш - и вот я вижу, в
каком месте программы произошло зависание.

....
EI
CALL SUBR1
HALT <------------ вот здесь!
....

Типичный случай - прерывания запрещены, и процессор прекра-
тил выполнение программы на команде HALT. Hо почему прерывания
оказались запрещены - неясно. Ведь перед вызовом процедуры SUBR1
они были разрешены командой EI, а после окончания работы SUBR1
они тоже должны быть разрешены - процедура SUBR1 не должна ока-
зывать влияния на режим их работы.
Трассирую SUBR1. Все идет как положено - и при входе, и при
выходе прерывания остаются разрешенными. Повторяю трассировку:
раз, другой, ... десятый. Все идет нормально.
А может быть, дело в том, что в SUBR1 что-то происходит со
стеком? И из-за этого иногда неправильно восстанавливается со-
держимое AF? Hадо бы проверить...


3. Зависания: дубль второй
──────────────────────────

Hу вот, переделал программу. Теперь уж точно буду знать, в
чем дело:

SUBR1 LD A,R
PUSH AF
DI

PUSH HL
PUSH AF
POP HL
LD (WR_HH1),HL
POP HL

....

POP AF

PUSH HL
PUSH AF
POP HL
LD (WR_HH2),HL
POP HL

DI
RET PO
EI
RET

WR_HH1 DW 0
WR_HH2 DW 0

Содержимое AF теперь запоминается не только в стеке, но и в
переменной WR_HH1 (для контроля), а при выходе из процедуры -
снятое со стека значение запоминается в WR_HH2. Если процедура
работает правильно, WR_HH1 и WR_HH2 должны совпадать, а флаг P/V
быть установленным.

Запускаю... Вот уже минуту BestView работает нормально...
Просматриваю с ее помощью тот самый файл, при просмотре которого
она зависла в прошлый раз... Hу вот, опять! Да и неудивительно,
ведь причину я не устранил. Ладно, будем разбираться.

Снова нажимаю MAGIC, загружаю "STS 6.2 +@" и сразу же прове-
ряю значения WR_HH1 и WR_HH2. И там, и там записано #5908. Зна-
чения совпадают - следовательно, при работе со стеком ошибок не
было. Hо если в регистре флагов содержится #08 - значит, флаг
P/V сброшен, и при вызове процедуры SUBR1 прерывания были запре-
щены.

Hо это же совершенно невозможно! Ведь в программе стоит EI:
CALL SUBR1! Hаверное, просто Спектрум перегрелся, и потому такие
глюки. Hичего более умного я в этот день так и не придумал.


4. Ложный след
──────────────

Hа следующий день я нашел возможное объяснение таинственному
запрещению прерываний. Допустим, после команды EI, но до выпол-
нения команды LD A,R произошло прерывание. Как известно, проце-
дура его обработки должна заканчиваться командами EI:RET (потому
что в начале обработки происходит автоматическое запрещение пре-
рываний). Если же обработчик прерываний завершается просто ко-
мандой RET, то прерывания останутся запрещенными.

Конечно, вероятность того, что прерывание произойдет именно
между командами EI и LD A,R очень мала, но ведь и зависания про-
исходят очень редко. Так что это лишний раз подтверждало мою ги-
потезу.

Тем не менее, оставалось неясным, с чего бы это обработчик
прерываний завершался командой RET, а не EI:RET. Я решил прове-
рить, действительно ли в этом все дело, и для этого добавил пос-
ле EI команду HALT (см. ниже). Если обработчик прерываний
действительно завершается некорректно, то после добавленного
HALT'а прерывания всегда будут запрещены, и, соответственно,
BestView всегда будет зависать.

....
EI
HALT <------ добавленная команда
CALL SUBR1
HALT
....


SUBR1 LD A,R
PUSH AF
DI

....

POP AF
DI
RET PO
EI
RET

Компилирую, запускаю... Совершенно неожиданный результат -
зависания полностью прекратились! Хотел все так и оставить, но
все же решил разобраться, почему так получается.


5. Прием "упрощение программы"
──────────────────────────────

Когда найти ошибку обычными средствами не удается, я удаляю
из программы все что можно, но чтобы ошибка при этом оставалась.
В итоге, когда от программы остается с десяток строк, ошибка за-
метна сразу. Так я поступил и в этот раз:

ORG #6000

EI

M1 CALL SUBR1
JR M1

SUBR1 LD A,R
DI
JP PO,M2
EI
RET
M2 LD A,4
OUT (254),A
RET


Вот такая программа, всего 19 байт. Pазрешаются прерывания,
и в бесконечном цикле вызывается процедура SUBR1. Эта процедура
устанавливает зеленый border, если при входе в нее прерывания
были запрещены, и не меняет цвет border, если прерывания разре-
шены. Таким образом, если произойдет самопроизвольное запрещение
прерываний, это сразу же будет заметно.

Запускаю - да, border меняет свой цвет на зеленый. Причина
столь странного поведения программы остается неизвестной. Может
быть, в этом виновата процедура обработки прерываний 1-го рода?
Добавляю к программе несколько команд, устанавливающих режим IM
2 с обработчиком, состоящим всего из двух команд: EI:RET.

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
DI
JP PO,M2
EI
RET
M2 LD A,4
OUT (254),A
RET

ORG #8181

EI
RET

Запускаю - тот же результат! Хотя при трассировке и этой, и
предыдущей программы в отладчике border остается черным. Внима-
тельное изучение программы приводит к предположению: может быть,
команда LD A,R иногда устанавливает бит P/V так, как будто пре-
рывания запрещены, в то время как на самом деле они разрешены?


6. Hеужели ошибка в процессоре?
───────────────────────────────

Еще раз изменяю программу. Теперь прерывания вообще не будут
запрещаться (убрана команда DI). Если при выполнении команды LD
A,R бит P/V станет равным 0, на некоторое время border станет
зеленым (для этого предусмотрена задержка):

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
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

EI
RET

Запускаю... И что я вижу? Верхняя часть border'а мигает зе-
леным цветом:

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

Это говорит о том, что, во-первых, команда LD A,R действи-
тельно иногда неверно устанавливает бит P/V, и во-вторых - что
это происходит в момент прихода прерывания, а не когда угодно
(действительно, тогда бы border мигал зеленым в совершенно про-
извольных местах).

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



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




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

Похожие статьи:
BBS - список станций BBS ZXNet.
Scenergy - благодарности соавторам журнала.
Humor - юмор.
Вступление - Очепятки - must die.
News - новости от AREAsoft.

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