Adventurer #04
31 июля 1996

Обмен опытом - "С точностью до ..." : о прерываниях; дисковые загрузчики.

            ╔───────────────╗
    ╔─────┬─╝       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  - число секторов.






     Надеюсь, Вы поняли, что к чему и Вам
не  понадобится  следующая  статья, чтобы
написать свой крутой загрузчик.
     Еще  хотелось  бы  сказать несколько
слов:
     Те  из  Вас,  кто  набил и опробовал
загрузчик наверное заметили, что он ужас-
но медлителен, даже  при запрещенных пре-
рываниях.
     Это говорит  лишь об одном - ищите и
дерзайте!  НИКОГДА НЕ БОЙТЕСЬ ЭКСПЕРИМЕН-
ТИРОВАТЬ!  В разумных пределах, конечно!

                 * * * 




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

Похожие статьи:
Водолей - Программисты... с точки зрения подхода к работе.
Часть вторая - Всиго Панимношку...
Реклама - бесплатная реклама и объявления...

В этот день...   21 октября