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 ноября