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 неправильно работает лишь тогда, когда импульс прерывания приходит во время ее выполнения, а так бывает далеко не всегда - прерывание может произойти и во время выполнения другой команды. =============================================================================




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

Похожие статьи:
Железо - Схемa KEMPSTON MOUSE.
Internet - "Виртуальные композиторы" о трекерах и музыкантах.
Spectrum Scene - Gas13, LaZy Bones и Vivid рассуждают о сцене, сценерах и о себе.
NEWS - Новости Коврова и Владимирской области. О прошедших party: Chaos Construction'999, Doxycn'99, Cafe'99, Di-Halt'99, Paradox'99, Phat'99.
От авторов - Краткое описание возможностей оболочки.

В этот день...   8 мая