(c) Иван Рощин, г.Москва, 1997
Особенности отладки программ
с помощью монитора STS
Наверняка у каждого програм-
миста при отладке своего творе-
ния возникала мысль: хорошо бы в
любой момент работы отлаживае-
мой программы при нажатии опре-
деленной комбинации клавиш вый-
ти в отладчик (например, чтобы
посмотреть значения переменных),
а затем как ни в чем не бывало
вернуться к выполнению програм-
мы. В ZX-РЕВЮ уже были статьи на
эту тему (например, на стр.244
за 1991г., на стр.33 за 1993г.).
Здесь я хочу рассказать о приме-
нении для этой цели наиболее
популярного монитора-отладчика
STS.
В этом отладчике существует
возможность поставить в отлажи-
ваемой программе точку останова,
при достижении которой происхо-
дит выход в STS. Рассмотрим под-
робнее, что происходит при уста-
новке точки останова (с помощью
клавиши "W"), и при выходе в
STS, когда отлаживаемая програм-
ма достигла точки останова.
При установке точки останова:
1) Из ячеек ADR_W и ADR_W+1 бе-
рется адрес предыдущей точки
останова.
2) По этому адресу заносится со-
держимое трех байтов памяти,
ранее (при установке предыду-
щей точки останова) запомнен-
ных в ячейках ADR_B-ADR_B+2.
3) В ячейки ADR_W и ADR_W+1 за-
сылается адрес, отмеченный
курсором.
4) В ячейки ADR_B-ADR_B+2 зано-
сится содержимое трех байтов
памяти, начиная с адреса, от-
меченного курсором.
5) По адресу, отмеченному курсо-
ром, заносится команда JP
ADR_OST.
Когда выполняемая программа
достигает точки останова:
1) Происходит переход на адрес
ADR_OST, и управление пере-
дается резидентной части STS.
2) STS запоминает содержимое
всех регистров, режима преры-
ваний и т.п.
3) Из ячеек ADR_W и ADR_W+1 бе-
рется адрес точки останова.
4) По этому адресу заносится со-
держимое трех байтов памяти,
ранее (при установке этой
точки останова) запомненных в
ячейках ADR_B-ADR_B+2.
5) Вы можете работать в STS.
Приведенной информации впол-
не достаточно, чтобы написать
фрагмент программы, который при
нажатии некоторой комбинации
клавиш (например, "SS+D" - от
слова "Debugger") обеспечивает
вход в STS с возможностью
дальнейшего продолжения работы
отлаживаемой программы. Нужно
только знать адреса ADR_W, ADR_B
и ADR_OST. Отмечу, что в разных
версиях STS эти адреса разли-
чаются, а адрес ADR_OST зависит
еще и от расположения резидент-
ной части STS в памяти. Чтобы
найти ADR_OST, достаточно посмо-
треть, какую команду STS поста-
вит при нажатии клавиши 'W'.
Чтобы найти ADR_B, можно, ска-
жем, записать по какому-то адре-
су памяти байты #AB,#CD,#EF, по-
том поставить по этому адресу
точку останова и найти адрес, по
которому STS сохранил эти три
байта. Чтобы найти ADR_W, нужно
поставить по какому-нибудь адре-
су (например, #8000) точку оста-
нова, а потом посмотреть, где
эти два байта (#00, #80) хранят-
ся внутри STS.
Привожу адреса для пяти из-
вестных мне версий STS (при ус-
ловии, что резидент находится по
адресу #5B90):
ADR_W ADR_B ADR_OST
STS 3.2 #DFC3 #DFE4 #5B98
STS 3.3 #DFC3 #DFE4 #5B98
STS 4.1 #E064 #E07C #5B9B
STS 4.3 #E06E #E088 #5B9B
STS 5.1 #E02E #E038 #5B9B
Приведенный ниже фрагмент вы
можете вставить в отлаживаемую
программу, например, после про-
цедуры опроса клавиатуры или в
другом часто выполняемом месте.
Хочу заметить, что адрес его
расположения в памяти должен
быть меньше #C000, т.к. в этом
фрагменте переключаются банки
ОЗУ.
140.
ADR_W EQU #E02E ;ЭТИ АДРЕСА ДАНЫ ДЛЯ
ADR_B EQU #E038 ;STS ВЕРСИИ 5.1, ЕСЛИ РЕЗИДЕНТ
ADR_OST EQU #5B9B ;НАХОДИТСЯ ПО АДРЕСУ #5B90.
BANK_S EQU #1F ;БАНК STS
BANK_D EQU #18 ;БАНК ОТЛАЖИВАЕМОЙ ПРОГРАММЫ
LD BC,#7FFE ;АДРЕС ПОРТА КЛАВИАТУРЫ
IN A,(C) ;ПРОВЕРЯЕМ, НАЖАТА ЛИ "SYMB.SHIFT"
BIT 1,A ;ЕСЛИ ДА, ФЛАГ Z УСТАНОВЛЕН
JR NZ,NEXT_C ;ЕСЛИ НЕ НАЖАТА, ВЫХОДИМ...
LD B,#FD ;ИЗМЕНЯЕМ АДРЕС ПОРТА
IN A,(C) ;АНАЛОГИЧНО ПРОВЕРЯЕМ
BIT 2,A ;КЛАВИШУ "D".
JR NZ,NEXT_C ;ЕСЛИ НЕ НАЖАТА, ВЫХОДИМ...
LD BC,#7FFD ;УСТАНАВЛИВАЕМ БАНК, В
LD A,BANK_S ;КОТОРОМ НАХОДИТСЯ STS.
OUT (C),A
140.
;ИМИТИРУЕМ ДЛЯ STS ТОЧКУ ОСТАНОВА:
LD HL,ADR_B ;ЗДЕСЬ ХРАНЯТСЯ 3 БАЙТА,
;ЗАПОМНЕННЫЕ ПРИ УСТАНОВКЕ
;ПРЕДЫДУЩЕЙ ТОЧКИ ОСТАНОВА.
LD DE,(ADR_W) ;АДРЕС, ПО КОТОРОМУ ИХ НАДО
;РАЗМЕСТИТЬ (ОБЯЗАТЕЛЬНО НИЖЕ #C000)!
LD BC,3
LDIR ;ВОССТАНАВЛИВАЕМ 3 БАЙТА
LD HL,NEXT_C ;АДРЕС ПЕРВОЙ КОМАНДЫ, КОТОРАЯ
LD (ADR_W),HL ;БУДЕТ ВЫПОЛНЕНА ПОСЛЕ ВЫХОДА
;ИЗ STS, ЗАПИСЫВАЕМ В ЯЧЕЙКИ
;ADR_W..ADR_W+1 (В НИХ STS ХРАНИТ
;АДРЕС, ПО КОТОРОМУ БЫЛА УСТАНОВЛЕНА
;ТОЧКА ОСТАНОВА).
LD DE,ADR_B ;В ЯЧЕЙКАХ ADR_B..ADR_B+2 STS ХРАНИТ
LD BC,3 ;3 БАЙТА, РАСПОЛОЖЕННЫЕ ПО АДРЕСУ
LDIR ;ТОЧКИ ОСТАНОВА.
LD A,BANK_D ;ВОЗВРАЩАЕМ БАНК, КОТОРЫЙ БЫЛ
OUT (C),A ;ДО ЭТОГО.
JP ADR_OST ;ТОЧКА ОСТАНОВА.
NEXT_C ... ;ОТСЮДА НАЧНЕТСЯ ВЫПОЛНЕНИЕ ПОСЛЕ
;ВЫХОДА ИЗ STS.
2
После нажатия "SS+D" и выхо-
да в STS все регистры принимают
значения, которые были на момент
прерывания программы, так что
можно будет продолжить ее выпол-
нение.
В процессе отладки можно
поставить в программе точку ос-
танова, лишь бы в момент работы
приведенного выше фрагмента
(когда удаляется старая точка
останова и ставится новая) адрес
старой точки останова был ниже
#C000.
Вы можете продолжить выпол-
нение отлаживаемой программы с
того места, где она была оста-
новлена, например, в пошаговом
режиме ("SS+Z", "SS+X", "SS+T")
или используя окно Trace, или с
помощью комбинации клавиш "SS+J"
(в версиях STS ниже 4.0 ис-
пользуйте "J", установив адрес
запуска равным содержимому PC,
или используйте комбинацию
"SS+K", но при этом останется
экран STS). Если вы хотите вер-
нуться в ассемблер, Бейсик или
TR-DOS, используйте клавишу "Q".
Если ваша программа зави-
сает неизвестно почему, STS то-
же может вам помочь. Для этого
вы должны встроить фрагмент, по-
добный описанному выше, в проце-
дуру обработки прерываний 2-го
рода. Предлагаю вашему вниманию
уже готовую процедуру обработки
прерываний, которая так же, как
и описанная выше, проверяет факт
нажатия "SS+D" и выходит в STS.
После выхода из STS выполнение
отлаживаемой программы будет
продолжено с того места, где оно
было прервано процедурой обра-
ботки прерывания. Поэтому, нахо-
дясь в STS, вы можете опреде-
лить, какой фрагмент программы
послужил причиной "зависания",
по содержимому регистра PC.
Ограничение на адрес распо-
ложения процедуры в памяти та-
кое же, как и у ранее описанно-
го фрагмента.
140.
ADR_W EQU #E02E ;ЭТИ АДРЕСА ДАНЫ ДЛЯ
ADR_B EQU #E038 ;STS ВЕРСИИ 5.1, ЕСЛИ РЕЗИДЕНТ
ADR_OST EQU #5B9B ;НАХОДИТСЯ ПО АДРЕСУ #5B90.
BANK_S EQU #1F ;БАНК STS
BANK_D EQU #18 ;БАНК ОТЛАЖИВАЕМОЙ ПРОГРАММЫ
EX (SP),HL ;АДРЕС ВОЗВРАЩЕНИЯ ИЗ ПРЕРЫВАНИЯ
LD (M1+1),HL ;ЗАПИСЫВАЕМ В ЯЧЕЙКИ M1+1 и M1+2
EX (SP),HL
PUSH AF ;СОХРАНЯЕМ В СТЕКЕ
PUSH BC ;ЗНАЧЕНИЯ РЕГИСТРОВ
PUSH DE
PUSH HL
PUSH IX
PUSH IY
EXX
EX AF,AF'
PUSH AF
PUSH BC
PUSH DE
PUSH HL
CALL USER ;ЗДЕСЬ МОЖЕТ БЫТЬ ОПРОС
;КЛАВИАТУРЫ, ВЫЗОВ МУЗЫКИ,
;В ОБЩЕМ, ВСЕ ЧТО ХОТИТЕ.
LD BC,#7FFE ;АДРЕС ПОРТА КЛАВИАТУРЫ
IN A,(C) ;ПРОВЕРЯЕМ, НАЖАТА ЛИ "SYMB.SHIFT"
BIT 1,A ;ЕСЛИ ДА, ФЛАГ Z УСТАНОВЛЕН
JR NZ,NEXT_C ;ЕСЛИ НЕ НАЖАТА, ВЫХОДИМ...
LD B,#FD ;ИЗМЕНЯЕМ АДРЕС ПОРТА
IN A,(C) ;АНАЛОГИЧНО ПРОВЕРЯЕМ
BIT 2,A ;КЛАВИШУ "D".
JR NZ,NEXT_C ;ЕСЛИ НЕ НАЖАТА, ВЫХОДИМ...
LD BC,#7FFD ;УСТАНАВЛИВАЕМ БАНК, В
LD A,BANK_S ;КОТОРОМ НАХОДИТСЯ STS.
OUT (C),A
;ИМИТИРУЕМ ДЛЯ STS ТОЧКУ ОСТАНОВА:
LD HL,ADR_B ;ЗДЕСЬ ХРАНЯТСЯ 3 БАЙТА,
;ЗАПОМНЕННЫЕ ПРИ УСТАНОВКЕ
;ПРЕДЫДУЩЕЙ ТОЧКИ ОСТАНОВА.
LD DE,(ADR_W) ;АДРЕС, ПО КОТОРОМУ ИХ НАДО
;РАЗМЕСТИТЬ
LD BC,3
LDIR ;ВОССТАНАВЛИВАЕМ 3 БАЙТА
M1 LD HL,0 ;АДРЕС ПЕРВОЙ КОМАНДЫ, КОТОРАЯ
LD (ADR_W),HL ;БУДЕТ ВЫПОЛНЕНА ПОСЛЕ ВЫХОДА
;ИЗ STS, ЗАПИСЫВАЕМ В ЯЧЕЙКИ
;ADR_W..ADR_W+1 (В НИХ STS ХРАНИТ
;АДРЕС, ПО КОТОРОМУ БЫЛА УСТАНОВЛЕНА
;ТОЧКА ОСТАНОВА).
LD DE,ADR_B ;В ЯЧЕЙКАХ ADR_B..ADR_B+2 STS ХРАНИТ
LD BC,3 ;3 БАЙТА, РАСПОЛОЖЕННЫЕ ПО АДРЕСУ
LDIR ;ТОЧКИ ОСТАНОВА.
LD BC,#7FFD
LD A,BANK_D ;ВОЗВРАЩАЕМ БАНК, КОТОРЫЙ БЫЛ
OUT (C),A ;ДО ЭТОГО.
POP HL ;ВОССТАНАВЛИВАЕМ
POP DE ;ЗНАЧЕНИЯ РЕГИСТРОВ
POP BC
POP AF
EXX
EX AF,AF'
POP IY
POP IX
POP HL
POP DE
POP BC
POP AF
EX (SP),HL ;УБИРАЕМ ИЗ СТЕКА
POP HL ;АДРЕС ВОЗВРАТА
EI
JP ADR_OST ;ТОЧКА ОСТАНОВА.
;ПОСЛЕ ВЫХОДА ИЗ STS ВЫПОЛНЕНИЕ ПРОГРАММЫ БУДЕТ
;ПРОДОЛЖЕНО С ТОГО МЕСТА, ГДЕ ОНО БЫЛО ПРЕРВАНО
;ПРОЦЕДУРОЙ ОБРАБОТКИ ПРЕРЫВАНИЯ.
NEXT_C ;ЕСЛИ ВЫЗОВ STS НЕ ПОНАДОБИЛСЯ:
POP HL ;ВОССТАНАВЛИВАЕМ
POP DE ;ЗНАЧЕНИЯ РЕГИСТРОВ
POP BC
POP AF
EXX
EX AF,AF'
POP IY
POP IX
POP HL
POP DE
POP BC
POP AF
EI
RET ;И ВЫХОДИМ ИЗ ПРЕРЫВАНИЯ.
2
При отладке программ часто
используют совместно STS и ас-
семблер (TASM, MASM, ZX ASM и
т.п.), что очень удобно. Если в
вашу программу встроен один из
описанных выше фрагментов, вы
должны обратить особое внимание
на то, КАК вы запускаете прог-
рамму на выполнение. Если из
STS, все будет нормально в лю-
бом случае. Если же программа
запускается из ассемблера или
BASIC'а, у вас может не полу-
читься выйти в STS при нажатии
"SS+D", или вы выйдете в STS, но
не сможете продолжить выполне-
ние программы.
───────────────
Известно, что пошаговое вы-
полнение команд процессора в STS
осуществляется тремя способами:
с помощью комбинаций клавиш
"SS+Z","SS+X" и "SS+T". Попробую
рассказать об особенностях этих
способов и о том, когда лучше
использовать каждый из них:
1) "SS+Z" - происходит поша-
говое выполнение команд про-
цессора Z80. Никаких сложнос-
тей при использовании "SS+Z"
быть не должно, только не
трассируйте команду HALT,
когда запрещены прерывания -
иначе компьютер зависнет.
2) "SS+X" - то же, что и "SS+
Z", но команда CALL будет вы-
полнена непосредственно, без
трассировки вызываемой под-
программы, которая предпола-
гается уже отлаженной. Это же
касается и команды RST (кста-
ти, в описании STS'а упомина-
ется только CALL, а об RST
нет ни слова). Выполняемая
команда может находиться и в
ОЗУ, и в ПЗУ. Это лучший спо-
соб для выполнения отлаженных
подпрограмм, но у него есть
одна особенность: так как вы-
зов подпрограммы происходит
из резидента, в стек вместо
адреса следующей выполняемой
команды вашей программы будет
занесен адрес для возврата в
резидент. Почти всегда это не
имеет никакого значения, но
некоторые подпрограммы могут
использовать содержимое сте-
ка. Например, при отладке
своих программ я часто ис-
пользую подпрограмму, которая
при своем вызове печатает на
экране содержимое регистров
процессора в момент вызова.
Чтобы определить значение PC,
она анализирует, какой адрес
был занесен в стек при ее вы-
зове.
3) "SS+T" - отладчик ставит
после выполняемой команды,
которая не может находиться в
ПЗУ, точку останова и запус-
кает отлаживаемую программу.
По этой точке программа воз-
вращается через резидент в
STS.
"SS+T" удобно применять для
трассировки DJNZ, но для трасси-
ровки подпрограмм (CALL, RST)
лучше этот способ не использо-
вать, т.к. может случиться не-
приятность. Это видно на следую-
щем примере:
140.
#8000: CALL #8004
#8003: RET
#8004: LD A,7
#8006: OUT 254,A
#8008: RET
2
Эта программа должна устано-
вить белый цвет бордюра. Если
выполнить ее в пошаговом режиме
с помощью "SS+Z", можно убе-
диться, что именно это она и де-
лает. Однако, если выполнить ее,
нажав "SS+T", ожидаемого ре-
зультата вы не получите. Для то-
го, чтобы понять, почему это
происходит, подробнее разберем
алгоритм работы отладчика при
нажатии "SS+T":
- после текущей команды (в
данном случае CALL #8004) ста-
вится точка останова (команда
JP, занимающая 3 байта). Бывшие
на этом месте 3 байта запомина-
ются.
- передается управление по ад-
ресу #8000;
- при достижении точки остано-
ва происходит возврат в отлад-
чик, запомненные 3 байта восста-
навливаются.
Все бы хорошо, но в рассмат-
риваемом случае 3 байта команды
JP накладываются на адрес, по
которому передается управление в
команде CALL #8004. В результа-
те этого реально выполняется
следующая последовательность ко-
манд:
140.
#8000: CALL #8004
#8004: SBC A,E
#8005: LD E,E
#8006: OUT (254),A
#8008: RET
#8003: JP #5B9B
2
Разумеется, все вышесказан-
ное относится и к команде про-
цессора DJNZ, так что "SS+T"
нужно применять с осторожностью.
Вот, например, какая может быть
ситуация при трассировке DJNZ:
140.
#8000: LD B,#00
#8002: LD A,(#800A)
#8005: OUT (#FE),A
#8007: DJNZ #8002
#8009: RET
#800A: DB 0 ;БАЙТ ИСПОРТИТСЯ
2
───────────────
Теперь поговорим о пошаговой
трассировке (окно Trace). В этом
окне есть параметр Trace Call.
Если он включен, отладчик будет
заходить "внутрь" процедуры при
каждом выполнении команды CALL
или RST (эмулируется "SS+Z"), а
если выключен - выполнять ее с
помощью прямого запуска из рези-
дента ("SS+X"). Мне кажется, бы-
ла бы полезной возможность неза-
висимо от значения Trace Call
отключить трассировку подпрог-
рамм, адреса которых выходят за
заранее определенные границы.
Эти границы должны указываться в
окне Trace. Например, если ниж-
няя граница равна #4000, а верх-
няя #FFFF, то отладчик не будет
заходить "внутрь" всех подпрог-
рамм ПЗУ. Но так как этой воз-
можности в STS нет, остается
только надеяться, что она будет
в одной из следующих версий.
* * *
(c) Иван Рощин, г.Москва, 1997
Исправление ошибки STS 5.1
В отладчике STS 5.1 есть
ошибка, из-за которой нельзя
нормально редактировать содержи-
мое памяти в символьном виде.
Рассмотрим пример: пусть по ад-
ресу #8007 нужно поместить код
символа "P":
┌────────────────────────────────────────┐
│#8000 00 00 00 00 00 00 00 00 ▒▒▒▒▒▒▒▒│
│#8008 00 00 00 00 00 00 00 00 ▒▒▒▒▒▒▒▒│
Входим в режим редактирования и
указываем символ "P":
┌────────────────────────────────────────┐
│#8000 00 00 00 00 00 00 00 00 ▒▒▒▒▒▒▒P│
│#8008 00 00 00 00 00 00 00 00 ▒▒▒▒▒▒▒▒│
Но после нажатия 'ENTER' ожидае-
мого результата не получим...
┌────────────────────────────────────────┐
│#8000 50 00 00 00 00 00 00 00 P▒▒▒▒▒▒▒│
│#8008 00 00 00 00 00 00 00 00 ▒▒▒▒▒▒▒▒│
Для исправления этой ошибки
необходимо внести следующие из-
менения в файл "sts5.1a":
140.
- начиная с адреса #DE1C
ввести команды:
CALL #E681
NOP
NOP
NOP
- по адресу #E67F поместить
байты #2E,#00;
- начиная с адреса #E681
ввести команды:
JP Z,#E5BD
OR C
JP #E590
2
При этом приходится жертво-
вать частью текстового сообщения
"File exist, overwrite...", от
которого в итоге останется лишь
"File exist,over.".
* * *