╔───────────────╗
╔─────┬─╝ C ╚─┬─────╗
────╣ ────╬─── точностью ───╬──── ╠────
╚─────┴─╗ до... ╔─┴─────╝
╚───────────────╝
(C) Заводчиков Константин
(C) Музыка D.J.MUSIC
Точность - вежливость
королей
Привет всем,кто читает эту статью. И
в этот раз я буду нести какую-то "пургу",
но немного на более серезную тему. Это -
прерывания. Вернее, как можно измерить
время работы программы с помощью преры-
ваний. Лично мне известны три способа из-
мерения времени работы программы (под вы-
ражением "время работы" подразумевается
количество тактов процессора). "Тянуть
резину" не буду, а начну сразу же "обме-
ниваться опытом". Итак, преступим-с.
Самый точный и самый простой(?) ме-
тод это - такой метод (прим.: точность
результатов измерений будет напрямую за-
висеть от вас и вашего самочувствия). От-
личные показатели этот метод дает на не-
больших (под)программах. Суть данного
метода заключается в следующем : загружа-
ете или MONS(1-4), или MON2, или STS, ко-
му что нравится (или у кого что есть),
размещаете свою (хорошо, коли так) прог-
рамму по любому понравившемуся адресу,
значение памяти устанавливаете на этот
адрес, включаете дизассемблер программы и
... Тут-то и начинается самое интересное
(маленький совет : если вы не помните,
сколько тактов занимает та или иная ко-
манда, тогда возьмите книгу с этими дан-
ными, но если такой книги нет и память
ваша вас подвела, то этот метод не для
вас). Так вот,о самом интересном(?). Пос-
ле того, как был включен дизассемблер, вы
начинаете складывать такты всех команд,
с учетом циклов. Получившаяся сумма - это
и есть то время, которое занимает ваша
программа.
Вроде, первый метод разобрали (кому
что неясно, обращайтесь в редакцию). Пой-
дем дальше. Второй метод тоже несложный,
но вдобавок и не очень точный (разброс
+/- 5000 тактов,как не больше). В принци-
пе, этот метод рассчитан на то, чтобы оп-
ределить, перебралась ваша прога тысяч
тактов, этак за 70, или нет. А если ис-
пользовать этот способ совместно с мето-
дом, описанным в ZX-FORMAT N3 в статье по
АССЕМБЛЕРу в главе, не помню какой, можно
добиться хороших результатов.
Суть такова: перед стартом процедуры,
о резвости которой вам интересно узнать,
устанавливаете бордюр в какой-нибудь
цвет, к примеру, зеленый или белый (ко-
му что или кому как). После выполнения
вашей программы установите бордюр черного
цвета. Но не забудьте, что эта ваша
программа в месте с переключениями цвета
бордюра должна быть повешена на прерыва-
ния или, в крайнем случае, все это безоб-
разие должно начинаться с команды HALT !
Это выглядит примерно так:
EI
BEGIN HALT
LD A,4
OUT (#FE),A
CALL PROG
XOR A
OUT (#FE),A
IN A,(#FE)
CPL
AND #1F
JR Z,BEGIN
........
Полоса зеленого цвета на бордюре и будет
показывать, сколько времени тратится на
вашу программу. Если весь бордюр зеленый,
то ваша программа перебралась за 70000
тактов. Если только полбордюра зеленые,
тогда программка убралась в 30000-40000
тактов и т.д. и т.п.
Ладно, теперь серьезно. Статья, во-
обще-то, и задумывалась, в основном,
только из-за этого метода, т.к. с его по-
мощью можно измерить время исполнения
программы с точностью до четырех тактов
процессора ! У кого-то, может быть, воз-
никнет вопрос: "Почему с точностью до че-
тырех, а не до одного такта ?" Как я ду-
маю, сначала стоит ответить на этот воп-
рос, чтобы не было каких-нибудь недоразу-
мений.
Все, в основном, исходит от прерыва-
ний, т.к. метод рассчитан на их использо-
вание. Когда в компьютере вырабатывается
сигнал INT, процессор начинает соображать,
что пора отвлечься от исполнения основной
программы, и стоит заняться чем-нибудь
другим, не менее полезным. Этот самый
сигнал INT (маскируемые прерывания) может
поступить в любое время, даже во время
исполнения процессором какой-нибудь ко-
манды. Но как "человек" добропорядочный,
процессор сначала выполнит начатое до
конца, а затем уж и отвлечется. А т.к.
любая команда занимает какое-то количес-
тво тактов (минимум четыре), то поэтому
и не получается точности измерений до од-
ного такта. Сам собой напрашивается дру-
гой вопрос : "Тогда почему именно четыре,
а не семь, десять или двадцать тактов ?"
Вообще-то, точность до четырех тактов га-
рантирована только программам, которые
убираютя в промежуток между прерываниями.
Другие же будут просто прерваны, но коли-
чество тактов будет чуть больше, чем чис-
ло тактов между прерываниями (всего нес-
колько тактов). А почему именно четыре
такта, можно узнать чуть дальше.
DI
LD A,#FE
LD I,A
IM 2
LD HL,INT
LD (#FEFF),HL
EI
HALT
....
END
DEFS 18000
INT ; кол-во тактов
PUSH HL ;11
LD HL,NEXT ;10
DEC (HL) ;11
POP HL ;10
EI ;4
RET NZ ;5
LD DE,END
POP HL
AND A
SBC HL,DE
LD (DATA),HL
IM 1
RET
DATA
DEFW 0
NEXT
DEFB 2
После того как, эта процедура отработала,
в ячейке DATA появляется количество ко-
манд NOP, которые успели выполниться
после вашей программы. Умножив это число
на четыре, получаем количество свобод-
ных тактов, оставшихся от вашей програм-
мы. А теперь, вычтя из числа тактов между
двумя прерываниями только что рассчитан-
ное число плюс еще 51 такт, получаем ко-
личество тактов, занимаемых вашей прог-
раммой. Но если в ячейке DATA число очень
большое, то значит, что ваше изобретение
не хочет делать свои дела за 70000 так-
тов.
Примечание: все действия, описанные
после листинга программы, нужно делать
вручную на калькуляторе, т.к., возможно,
могут получиться числа, больше чем воз-
можны в машинном коде, т.е. больше 65535!
───────────────────────────────
╔───────────────╗
╔─────┬─╝ Спрашиваете - ╚─┬─────╗
────╣ ────╬───═════════════───╬──── ╠────
╚─────┴─╗ отвечаем ╔─┴─────╝
╚───────────────╝
А теперь небольшие ответы на воз-
никающие у народа вопросы на ту или иную
тему по программированнию.
Вопрос: "Почему когда запрещаешь прерыва-
ния первого рода или переходишь на вто-
рые прерывания, в ячейке LAST_KEY инфор-
мация не меняется ?"
Ответ: "Все очень просто! На первые пре-
рывания повешена процедура опроса клавиа-
туры, поэтому-то и не меняется информа-
ция в LAST_KEY при отключении первых пре-
рываний. Так что, если вам нравится поль-
зоваться этой системной переменной, тогда
оставьте в покое первые прерывания. Но
если вам надо повесить что-то свое на
прерывания второго рода, а та ячейка вам
так симпатична, что нет никакого желания
отказываться от нее, тогда в конце своей
процедуры обработки прерываний ставьте не
команду RET, а JP #0038. И еще, если вы
пользуетесь первыми прерываниями, то ни
за что не трогайте регистр IY ! В нем
постоянно должно находиться число 23610,
тогда, глядишь,и в LAST_KEY все будет OK.
Но все равно, я бы посоветовал не извра-
щаться, а пользоваться более лучшим ме-
тодом. Тогда вам будет наплевать на то,
что находится в IY и какие включены пре-
рывания. Это выглядит так:
CALL #028E
CALL #031E
После выполнения двух этих подпрограмм,
в регистре A возвращается основной код
нажатой клавиши, т.е. код заглавной бук-
вы латинского алфавита или код цифры. Но
если в аккумуляторе находится код #18,
тогда нажата только клавиша SYMBOL SHIFT.
Если там код #27, значит нажат CAPS SHIFT
или, если в A код #0E, тогда нажаты и
CAPS SHIFT, и SYMBOL SHIFT. Стоит обра-
тить внимание и на регистр B. Если в
нем находится #18, значит была нажата ка-
кая-то клавиша с SYMBOL SHIFT. А если
там (в регистре B ) есть число #28, тогда
была нажата клавиша с CAPS SHIFT. Ну вот
отсюда можно сделать соответствующие вы-
воды."
Вопрос: "В одном из прошлых номеров жур-
нала ADVENTURER были опубликованы точки
входа некоторых процедур ПЗУ. Вот, к
примеру, подпрограмма CLEAR не работает
из режима 128К. Следующая процедура вы-
полняет те же действия, но работает прек-
расно во всех режимах:
LD BC,#1303
PUSH BC
LD BC,STACK
CALL #1EB7
Хотелось бы получить объяснение по этому
поводу, т.е. почему некоторые процедуры
ПЗУ отказываются работать в 128К."
Ответ: "Такие глюки происходят из-за то-
го, что прошивка ПЗУ 48-ого BASIC'а в
SPECTRUM 128 была подправлена, т.к. эту
часть ПЗУ активно использует BASIC 128.
Поэтому-то, когда вы вызываете какую-ни-
будь процедуру из ПЗУ BASIC 48 в режиме
128К, начинают выполняться дополнительные
процедуры, которых изначально не было в
48-м BASIC'е. Но чтобы таких глюков из-
бежать, нужно обнулить всего лишь значе-
ние ячейки 23625. Теперь насчет выше-
приведенной процедуры. То, что заносится
на стек из BC - это адрес главного цикла
обработки команд BASIC'а, и заносить его
на стек не обязательно,т.к. на этот адрес
все равно потом будет сделан переход ин-
терпретатором BASIC'а. Ну а тот вызов
процедуры по адресу #1EB7 практически ни-
чем не отличается от того, что было напи-
санно во втором номере нашего журнала.
Отличие заключается в следующем: если в
регистре BC находится число "нуль" и выз-
вать процедуру по адресу #1EAF, тогда
число из системной переменной RAMTOP бу-
дет занесено в BC и очищены переменные
BASIC'a. А если с нулем в BC сделать вы-
зов программы с адреса #1EB7, тогда будет
сделан переход по ошибке "RAMTOP no good"
в BASIC ! Теперь, надеюсь, всем понятно
почему в нашем журнале была дана точка
входа в процедуру CLEAR по адресу #1EAF."
Вопрос: "Расскажите, пожалуйста, о памяти
SPECTRUM 128"
Ответ: "Я-то думал с этим вопросом давно
разобрались на страницах многих изданий,
но, похоже, что сильно ошибался. Так уж и
быть, вкратце коснусь этого вопроса. Са-
мое главное это то, что дополнительная
память компьютера переключается по порту
#7FFD (32765). В 128-ой машине восемь
страниц ОЗУ (с 0 по 7) по 16К каждая.
Любую из страниц ОЗУ можно установить с
адреса #C000 (49152), но стоит запомнить,
что вторая и пятая страницы закреплены
по адресам #8000 (32768) и #4000 (16384)
соответствено. Поэтому-то их нельзя ис-
пользовать как дополнительную память. Так
же существуют две страницы ПЗУ, содержа-
щие BASIC 48 и BASIC 128. Любая из этих
страничек может быть установлена только с
адреса #0000. В SPECTRUM 128 есть еще
один экран. Он находится в седьмой стра-
нице с самого ее начала.
А теперь раскладка бит порта #7FFD
(32765):
0-й, 1-й, 2-й биты ОЗУ, с их помощью
переключается дополнительная память;
3-й бит отвечает за то, какой экран
в данный момен активирован (если
бит сброшен, тогда работает основ-
ной экран, иначе включен второй эк-
ран из седьмой странички);
4-й бит - это выбор ПЗУ(бит включен,
выбран BASIC 48, иначе BASIC 128);
5-й бит - когда он включен значит,
вы находитесь в SPECTRUM 48 и поль-
зоваться дополнительной памятью не
можете;
6-й и 7-й биты не используются."
На этом я закончу разбор вопросов,
хотя таких накопилось немало, т.к. что-
то нет у меня сил продолжать эту писани-
ну, я же не литературный деятель. А те,
кто не получили ответа, не растраивай-
тесь, я отвечу на ваши вопросы либо уст-
но, либо в следующих номерах нашего жур-
нала.
╔───────────────╗
╔─────┬─╝ Дисковые ╚─┬─────╗
────╣ ────╬───═════════════───╬──── ╠────
╚─────┴─╗ загрузчики ╔─┴─────╝
╚───────────────╝
(C) Nicolas Viper
От редакции: эта статья готовилась как
продолжение материала о дисковых загруз-
чиках для журнала "Эльдорадо". Но так как
это издание прекратило свою деятельность,
Condor Soft любезно предоставил эти мате-
риалы для ADVENTURER'а.
А я, Nicolas Viper, снова с Вами.
Извините меня, что использую журнал для
личных целей, но если я еще услышу, что
меня называют - Николас Вампир - обижусь
и уйду на "Dendy". Уж если хотите знать,
то "Viper", кроме всего прочего перево-
дится как и "Adder" - гадюка (зоол.). Еще
раз дико извиняюсь, но мы отвлеклись.
Надеюсь, вы не забыли мой нудный
монолог во втором номере журнала
"Эльдорадо" ?
Вы ведь помните - я обещал расска-
зать о том, как сделать музыку во время
загрузки (и не только музыку), наподобие
того, как это делается в "INSULT",
"BATTLE COMMAND" и т.д. Конечно, мое из-
ложение страдает некоторой громоздкостью,
но ведь если не я, то кто же еще ?! Не
гениальный ли наш Nicodim ?
Надо сказать, что в прошлый раз я,
фактически, всего лишь пересказал книгу
Родионова и Ларченко "ZX-Spectrum & TR-
DOS для пользователей и программистов".
От себя я добавил только описание некото-
рых процедур ПЗУ ДОС. Сделал я это с од-
ной целью - подготовить Вас, дорогие чи-
татели, к этой статье.
В целом, программа, занимающаяся
ЭТИМ, схожа с той, которую мы рассматри-
вали в прошлый раз (взятую из "ZX-Ревю"
N4 за 1995). Но здесь есть проблема номер
раз: Необходимо, чтобы прерывания были
все время разрешены, а процедура по адре-
су #2F1B, к которой обращается наш
"loader" их запрещает (и правильно дела-
ет). Поэтому заменяем в программе:
...
LD IX,#2F1B
CALL DOS
...
на:
...
CALL LOA_COM
...
Т.е. вместо ПЗУ ДОС вызываем свою
процедуру, которую добавляем в конце:
LOA_COM
LD A,E ;преобразуем ном.
INC A ;сектора и посы-
LD C,#5F ;лаем его в порт
LD IX,#2A53 ;#5F (рег.секто-
CALL DOS ;ра)
TRY_1 ;
PUSH HL ;сохраняем на
PUSH DE ;случай ошибки
;
LD A,#80 ;#80-чт. сектора
LD C,#1F ;пишем в рег.ко-
LD IX,#2A53 ;манд
CALL DOS ;
LD C,#7F ;#7F-рег. данных
LD IX,#3FE5 ;чте
CALL DOS ; ние
{ Проверка правильности чтения (ППЧ) }
POP DE \
POP HL } (*)
RET /
Несложно заметить, что эта процедура
- переделка процедуры ПЗУ ДОС по адресу
#2F1B. Кусок помеченный, как (*), скорее
всего, войдет в процедуру ППЧ.
Здесь встает самая наиофигеннейшая
(во завернул!) проблема - "контроль пра-
вильности чтения". Полагаться в этом деле
на ДОС по-моему нельзя, т.к. там просто
не предусмотрен, например, вариант, когда
процедура по адресу #3FE5 (см. выше) м.б.
прервана в начале, середине или в конце
своей работы.
Короче, я хочу сказать, что делать
ЭТО придется вручную, т.е. либо записы-
вать на сектор 254-255 байт, а 1-2 отво-
дить под контрольные суммы (сокращенно
"КС"), либо грузить их ("КС") в начальном
этапе загрузки, когда Вы еще пользуетесь
#3D13, а потом в процедуре ППЧ посчитать
"КС" (звучит уморительно, не правда ли ?)
и сверить со считанной или табличной.
Как посчитать "КС" ? Это нетрудно.
Обычный метод - проксорить все байты друг
с другом - полученное число и есть "КС".
В общем, абсолютно точных рецептов я
Вам не дам. Если захотите, то в следующем
номере я дам ПОЛНЫЙ листинг рабочей про-
цедуры, набитой и проверенной лично мной.
Под конец, пример программы обра-
ботки прерываний:
ORG #FEFE
JP IM2_COM
...
CALL MUS_INIT ;б.к.
DI ;это установка
LD A,#FD ;2-ых прерываний
LD I,A ;(вдруг Вы не
LD HL,#FD00 ;знаете, как это
LD DE,#FD01 ;делать).
LD BC,256
LD (HL),#FE
LDIR
IM 2
EI
...
Здесь ваш (наш) загрузчик.
...
В конце добавляем:
...
IM2_COM
LD (STACK),SP
PUSH AF
...
PUSH ...
CALL MUS_PLY ;играет музыка
;<PRO TRACKER>
LD HL,(STACK) ;смотрим, куда
INC HL ;же мы возвра-
LD A,(HL) ;щаемся?
CP #40 ;
JR NC,RETRAM ;в ОЗУ
LD A,#C3 ;в ПЗУ
LABEL1 LD (CHANGE),A ;
POP ... ;код #C3 - JP
...
POP AF
CHANGE NOP ;тут ставим JP
DEFW #3D2F ; или RET
RETRAM LD A,#C9 ;код RET
JR LABEL1
STACK DEFW 0
───────────────────────────────
От редакции: Ниже приведен текст загруз-
чика из журнала "Эльдорадо" N2, на кото-
рый ссылается автор данной статьи. Вход-
ные данные : HL - адрес загрузки,
DE - дорожка и сектор,
B - число секторов.
Надеюсь, Вы поняли, что к чему и Вам
не понадобится следующая статья, чтобы
написать свой крутой загрузчик.
Еще хотелось бы сказать несколько
слов:
Те из Вас, кто набил и опробовал
загрузчик наверное заметили, что он ужас-
но медлителен, даже при запрещенных пре-
рываниях.
Это говорит лишь об одном - ищите и
дерзайте! НИКОГДА НЕ БОЙТЕСЬ ЭКСПЕРИМЕН-
ТИРОВАТЬ! В разумных пределах, конечно!
* * *