М.М.A/SPEED СО.
Был на свете такой хороший полиграфический
журнал "ZX-РЕВЮ" ..... Был, да как это ни
прискорбно, но весь вышел! И на пепелище
последнего его тиража, осталась
неопубликованной статья, написанная мной
и Максом Васильевым специально для этого
издания.
И хотя нижеследующий текст был набит ещё в
первых числах 1997-го года, он не потерял
той актуальности и остроты. Вот я и решил
включить этот материал в свежий номер ОБЕ-
РОН'а. Не пропадать же добру!
Правда была одна маленькая проблем-
ка....... Текст статьи написан языком
"ZX-РЕВЮ" и для читателей "ZX-РЕВЮ". ес-
тественно всё нужно было переделывать. Од-
нако, поскольку перспектива полного пере-
писывания статьи меня нисколько не
прельщала, я решил оставить всё как есть.
Итак, давайте "поскорбим" по безвременно
ушедшему от нас НАСТОЯЩЕМУ спектрумовскому
журналу - "ZX-РЕВЮ"!
(C) MAXSOFT / SPEED СО.
(C) М.М.A / SPEED СО.
г.Самара 1997 а.d.
ВООТ-программа в один сектор.
Со времён первых компьютеров с системой
TR-DOS , появившихся в нашей стране,
хаккеры и програмисты не перестают решать
великую проблему современности: зачем, как
и какой boot-загрузчик написать ??? Тех,
кто интересуется вопросом современного
boot-остроения, я позволю себе отослать к
статье, посвящённой именно этой теме, ко-
торая была опубликована в третьем номере
Самарского электронного журнала "ОБЕРОН".
В настоящей же статье, на примере написа-
ния boot-программы, мы рассмотрим вопросы
реализации сверхкоротких программ на ас-
семблере, а также возможность рацио-
нального использования процедур стан-
дартного ПЗУ и TR-DOS'а в подобных прог-
раммах.
Стоит отметить, что попытки создания
сверхкоротких boot-загрузчиков уже были, и
достаточно успешные. Например boot, напи-
санный Shi-soft'ом в 1992-ом году занимал
два сектора и вполне неплохо работал. Я
принципиально не говорю о длине в байтах,
так как в связи с использованием не кас-
сетных носителей информации (дискеты, и
как следствие, дисковые ОС, например
TR-DOS), понятие длины программы в байтах,
однозначно заменяется на понятие длины в
секторах. И в случае, если ваша процедура
имеет размер 260 байтов, а так же если
она будет занимать 460 байтов, всё равно
при записи на диск будет организован файл
объёмом в два сектора. Таким образом, если
ваша программа близко связана с DOS, имеет
смысл выбрать предельный её размер, крат-
ный размеру стандартного TR-DOS'овского
сектора и в последствии стараться ис-
пользовать каждый байт (бит) этого объёма
памяти.
Мы несколько отступили от темы, вернёмся
к нашим boot'ам! Другой пример boot-заг-
рузчика в два сектора - это программа
Д.Пьянкова SMALL ВООТ,распространяемая ИН-
ФОРКОМ'ом. Как пишется в описании на эту
программу : "Основная особенность - малый
объём (2 сектора), благодаря чему обеспе-
чивается быстрая загрузка". Вполне очевид-
но, что при размере в один сектор загрузка
будет ещё быстрее, а места на диске такой
boot вообще практически не занимает. Воп-
лощением именно этой, абсолютно казалось
бы безумной идеи и занялись сразу два са-
марских программиста.
Со времени возникновения этой идеи в моей
(М.М.A) голове прошло уже около полутора
лет. Так как в то время я был недостаточно
опытен в программировании, то просто поде-
лился мыслью о написании подобного шедевра
с другими самарскими программистами. В ре-
зультате, в жесткой конкурентной борьбе,
односекторный boot был не просто написан,
а написан настолько оптимально, что боюсь,
читателям "ZX-РЕВЮ" уже не удастся что-ли-
бо оптимизировать. Хотя, если не смотреть
листинг, приведённый ниже, а попробовать
реализовать эту идею, что называется с
"чистого листа", то, возможно, вам, доро-
гие читатели, удастся найти какие-либо но-
вые, нестандартные решения. Другое дело -
изменение функциональных особенностей...
Полный дизассемблер boot'а с комментариями
практически по каждой команде вы найдёте в
конце статьи. Там же находится дамп boot'а
и примечания по объединению кодового блока
и BASIC'а. Мы же продолжим тему изменений
и посмотрим, что и как можно поменять в
этой (базовой) версии boot'а.
В данной версии управление программой
осуществляется с помощью SINCLAIR
JOYSTICK'а и клавиш "Q","A","О","Р". Выбор
файла - "0","ENTER", чтение нового катало-
га - "SPACE". Как видно, управление от
SINCLAIR джойстика несколько излишне и при
желании вы можете его выкинуть и вставить
что-либо другое.
Например, неплохой эффект даст утолщённый
шрифт!
Хранить дополнительный символьный набор в
памяти - это уже три сектора (768 байт),
да и воспользоваться методиками создания
шрифтов с использованием стандартного ПЗУ
шрифта, не раз описанными в ZX-РЕВЮ, тоже
нельзя - слишком много байтов! Решение
должно быть нестандартным и одновременно
простым. А что, если сначала напечатать на
экране всё обычным шрифтом, а потом проде-
лать над экраном следующую операцию:
ORG 30000
LD HL,#4000
В HL- начальный адрес экрана
LOOP1 LD А,(HL)
Открываем цикл, грузим в A содержимое (HL)
SRL A
Сдвигаем A вправо (или SLA A - влево)
OR (HL)
Накладываем A на исходный байт в экране
LD (HL),A
Помещаем результат на экран
INC HL
Увеличиваем адрес в экране на единицу
LD A,Н
Загружаем в A значение Н,
СР #58
и смотрим, не дошло ли оно до старшего
разряда области атрибутов (#5800)
JR NZ,LOOP1
Повторяем цикл, если HL < #5800
RET Листинг l
В принципе, процедура на листинге l рабо-
тоспособна, и занимает всего 14 байт. Но
для сверхкороткого boot'а и этого много!
Дальнейшее совершенствование процедуры мо-
жет осуществляться путём изменения принци-
па определения конца экранной области.
Сам же алгоритм утолщения и так оптимален.
ORG 30000
LD HL,#57FF
В HL - самый последний байт экрана
LOOP1 LD A,(HL)
В А грузим содержимое (HL)
RRCA
Сдвигаем через RRCA (короче на один байт!)
OR (HL)
Накладываем на оригинал
LD (HL),A
Копируем обратно в экран
DEC HL
Уменьшаем HL *****
LD A,Н
Проверяем содержимое Н на 0
OR A
JR NZ,LOOP1
Если HL > #OOFF, то повторяем цикл
RET
Листинг 2
В данном случае отсчёт байтов идёт "снизу
вверх",и не заканчивается на #4000, а про-
ходит через всё ПЗУ (там,естественно,ниче-
го не изменяется) и доходит до адреса
#0100. Используя такой способ,мы экономим
ещё два победных байта и получаем процеду-
ру в 12 байт длиной.
Некоторое неудобство заключается в том,
что пока программа "идёт" через ПЗУ, тра-
тится достаточно большое количество тактов
процессора и пользователь начинает заме-
чать, как вы утолщаете символы. C одной
стороны это даже неплохо - получается
очень интересный эффект, но если он вам
кардинально не нравится, то попробуйте
следующее:
Сразу после команды DEC HL, помеченной в
предыдущем листинге, наберите :
BIT 6,Н
Проверяем, установлен ли шестой бит в
адресе, записанном в HL. Если установлен,
то продолжаем цикл, иначе - выходим.
JR NZ,LOOP1
RET
Для понимания работы этого условия поясню,
что все те адреса,которые могут находиться
в регистре HL при работе с экраном, имеют
выставленный шестой бит (#40 = %01000000),
а начиная с адреса #ЗFFF ( #3F =
%00111111) этот бит сброшен. По этому
принципу и работает определение конца эк-
ранной области. Байтов на этом мы не выиг-
рали, но зато работает побыстрее, чем вер-
сия с проверкой Н на 0. Но можно ли вооб-
ще сэкономить ещё? Естественно, можно !
Посмотрите в комментарии к листингу boota.
Там всё построено на том, что последующая
процедура использует данные предыдущей.
Если перед вызовом процедуры утолщения в
регистре L будет находиться число #FF, то
нам достаточно просто загрузить оставшуюся
половинку регистра - Н.
Поставьте в листинге 2 вместо LD HL,#57FF
команду LD Н,#57 и не забудьте, что в ре-
гистре L должно быть число #FF, оставлен-
ное от предыдущей процедуры. Вот мы и по-
лучили процедурку в 11 байтов - вполне
нормально для нашего односекторного дети-
ща. Вот только ситуация с регистром L не-
понятная. Нужно ли вообще его загружать ?
Если представить, что в регистре L к мо-
менту старта процедуры находится абсолютно
случайное число, то по окончании работы мы
просто получим неутолщёнными от одного до
#FF байтов в нижней трети экрана в нижней
части каждого знакоместа! Но в ПЗУ-шном
шрифте, насколько я помню, лишь запятая и
некоторые символы используют нижнюю строку
знакоместа. А так как эти символы в назва-
нии файла вообще редко встречаются, то
смело оставляем точно загруженным только
регистр Н.
ORG 30000
LD Н,#57
LOOP1 LD A,(HL)
RRCA
OR (HL)
LD (HL),A
DEC HL
BIT 6,Н
JR NZ,LOOP1
RET
Вот она - оптимизированная версия утолще-
ния всего экрана, которую вы, дорогие чи-
татели, можете вставлять в наш односектор-
ный boot вместо дополнительного управления
от SINCLAIR - джойстика.
Основной нашей целью было показать вам,как
нужно размышлять при написании сверхком-
пактного кода. К тому же мы хотим выбро-
сить идею односекторного boot'а на мозго-
вой штурм всей страны. В наших головах эта
идея дошла уже до полного оптимума. Но мы
будем очень рады, если кто-либо из читате-
лей предложит что-то новое,интересное, от
чего захочется, как в известной рекламе,
сказать : "СВЕЖО...."!
А вот и сам boot-загрузчик длиною в один
сектор:
ORG #5D3B
AUTHOR EQU #5D52
FILE_Р EQU #5D52
;BASIC СТРОКА ДЛЯ ЗАПУСКА
DEFB #00,#01,#F8,#00,#Е7,#C3,#A7,#3A
DEFB #F9,#C0,#В0,#22,#32,#33,#39,#30
DEFB #35,#22,#3A,#ЕА,#3A,#F7,#22
;ИНФОРМАЦИЯ ОБ АВТОРЕ(НЕ МЕНЕЕ 8 СИМВОЛОВ)
DEFB 23,11,32,"MAXSOFT'96"
DEFB #22 ;КОНЕЦ BASIC-СТРОКИ
DEFB #D ;"СВОБОДНЫЙ" БАЙТ
;1 SECTOR ВООТ
;IDEA ВУ М.М.A SOFT/SPEED СО.
;CODED ВУ MAXSOFT/SPEED СО.
LD (IY+#53),#5
;УСТАНОВКА ЦВЕТА PAPER В ЯЧЕЙКУ (#SC8D)
;BORDER УЖЕ УСТАНОВЛЕН ИЗ BASIC'A
NEW_DISK ;ЗАЧИТЫВАНИЕ ДИСКА
CALL #D6B ;ОЧИСТКА ЭКРАНА
;НА ВЫХОДЕ DE=#0000,HL=#50E0,ВС=#1721
;ЗАГРУЖАЕМ КАТАЛОГ ДИСКА С АДРЕСА #6801
ADD HL,ВС
LD ВС,#905
PUSH HL
CALL #3D13
;ПЕЧАТАЕМ ИНФОРМАЦИЮ ОБ АВТОРЕ
LD DE,AUTHOR
LD C,#D
CALL #203C
LD A,2
;ОТКРЫВАЕМ ПОТОК ПЕЧАТИ НА ЭКРАН
CALL #1601
РОР HL
LD D,Н
LD Е,L
SORT ;СОРТИРОВКА КАТАЛОГА
LD ВС,8
DEC (HL)
JR Z,NEXT_F ;СTЁРTЫЙ ФАЙЛ
INC (HL)
JR Z,END_SORT ;КОНЕЦ КАТАЛОГА
PUSH HL
ADD HL,ВС
LD A,(HL)
РОР HL
СР "В" ;ТИП ФАЙЛА
JR NZ,NEXT_F
PUSH HL
LD A,#20 ;ПЕЧАТЬ "ПРОБЕЛа"
RST #10
МАКЕ_FILE
LD A,(HL) ;ПЕЧАТЬ
RST #10 ;БУКВЫ
LDI ;И ЕЁ ПЕРЕНОС
JP РЕ,МАКЕ_FILE
;(ДЛЯ УПЛОТНЕНИЯ КАТАЛОГА)
LD HL,#70D1 ;СЧЁТЧИК ФАЙЛОВ
INC (HL)
LD A,(HL)
FILE_C
SUB 3
;ВЫЧИСЛЯЕМ, НАПЕЧАТАНО-ЛИ
;ТРИ ИМЕНИ ФАЙЛОВ В ОДНОЙ СТРОКЕ
JR Z,FILE_C1
JR NC,FILE_C
LD A,#20 ;НЕТ,НЕ НАПЕЧАТАНО
RST #10 ;-ПЕЧАТЬ "ПРОБЕЛа"
FILE_C1 ;ДА,НАПЕЧАТАНО
LD A,#20
RST #10
РОР HL
NEXT_F
LD C,#10 ;ПЕРЕХОДИМ
ADD HL,ВС ;К СЛЕДУЮЩЕМУ ФАЙЛУ
JR SORT
END_SORT ;КОНЕЦ СОРТИРОВКИ
NEW_CUR ;РЕГИСТР В=0
LD C,В
;РЕГИСТР С-СЧЁТЧИК ФАЙЛОВ
MOVE_CUR
LD HL,#57F5
LD DE,#В
XOR A
;РЕГИСТР A-ВРЕМЕННЫЙ СЧЁТЧИК
MOVE_C1
LD В,3
MOVE_C2
ADD HL,DE
;ВЫЧИСЛЯЕМ ПОЗИЦИЮ КУРСОРА
СР C
JR Z,CURSOR
INC A
DJNZ MOVE_C2
DEC HL
JR MOVE_C1
CURSOR ;РИСУЕМ КУРСОР
LD В,#A
LD DE,(#70D3)
LD (#70D3),HL
LD A,5
CURSOR1
LD (DE),A
;СТИРАЕМ СТАРЫЙ КУРСОР
INC DE
LD (HL),#16
;РИСУЕМ НОВЫЙ КУРСОР
INC HL
DJNZ CURSOR1
LD HL,#5C08
;ОБНУЛЯЕМ СИСТЕМНУЮ ПЕРЕМЕННУЮ (LAST-KEY)
LD (HL),В
KEYS ;ОПРОС КЛАВИШ
LD A,(HL)
СР " "
;ПРОБЕЛ-ПЕРЕЗAЧИTЫВAНИЕ ДИСКА
JR Z,NEW_DISK
СР #D
;ENTER-ЗАПУСК ПРОГРАММЫ
JR Z,START_F
СР "0"
;0-ЗАПУСК ПРОГРАММЫ
JR Z,START_F
СР "7"
JR Z,L_RIGHT
СР "6"
JR Z,L__LEFT
СР "8"
JR Z,L__DOWN
СР "9"
JR Z,L____UP
OR #20
;ВКЛЮЧЕНИЕ ВЕРХНЕГО РЕГИСТРА ДЛЯ БУКВ
;ОПРОС БУКВЕННЫХ КЛАВИШ НЕЗАВИСИМО ОТ
;РЕЖИМА "CAPS"
СР "р"
JR Z,L_RIGHT
СР "о"
JR Z,L__LEFT
СР "а"
JR Z,L__DOWN
СР "q"
JR NZ,KEYS
L____UP ;КУРСОР ВВЕРХ
DEC C
DEC C
L__LEFT ;КУРСОР ВЛЕВО
DEC C
JP Р,MOVE_CUR
;КУРСОР НЕ ДОШЁЛ ДО НАЧАЛА КАТАЛОГА
LD ВС,(#70D1)
;КУРСОР - НА КОНЕЦ КАТАЛОГА
DEC C
JR MOVE_CUR
L__DOWN ;КУРСОР ВНИЗ
INC C
INC C
L_RIGHT ;КУРСОР ВПРАВО
INC C
LD A,(#70D1)
DEC A
СР C
JR NC,MOVE_CUR
;КУРСОР НЕ ДОШЁЛ ДО КОНЦА КАТАЛОГА
JR NEW_CUR
;КУРСОР - НА НАЧАЛО КАТАЛОГА
START_F ;ЗАПУСК ФАЙЛА
LD A,C
INC A
LD C,L ;РЕГИСТР L=8
LD HL,#67F9
;АДРЕС НАЧАЛА КАТАЛОГА МИНУС 8
ST_F1
ADD HL,ВС
;ВЫЧИСЛЯЕМ ПОЗИЦИЮ ИМЕНИ ФАЙЛА В КАТАЛОГЕ
DEC A
JR NZ,ST_F1
LD DE,FILE_Р
;ПЕРЕНОСИМ ИМЯ ФАЙЛА В BASIC
LDIR
JP #3D03
;ВЫХОДИМ В BASIC С ЗАПУСКОМ ФАЙЛА
Листинг 4
l. НАБРАТь ТЕКСТ ВООТ'A В АССЕМБЛЕРЕ.
2. ВЫЙТИ В BASIC. СТЕРЕТь ВСЕ BASIC-СТРО-
КИ,ОТНОСЯЩИЕСЯ К АССЕМБЛЕРУ И СОЗДАТь
СВОЮ СТРОЧКУ ДЛИНОЙ 248 БАЙТ,Т.Е. КО-
МАНДА PRINT РЕЕК 23869 ДОЛЖНА ПОКАЗАТь
248.ПРИ ЭТОМ НЕЖЕЛАТЕЛьНО ИСПОЛьЗОВА-
НИЕ РЕДАКТОРА BASIC 128.
3. ВЕРНУТьСЯ В АССЕМБЛЕР И ПРОИЗВЕСТИ
АССЕМБЛИРОВАНИЕ.
4. ВЫЙТИ В BASIC И СОХРАНИТь BASIC-ПРОГ-
РАММУ :
RANDOMIZE USR 15619:REM:SAVE"1SBOOT"LINE 1
По поводу доработок и изменений.
В базовой версии boot'а,приведённой в лис-
tuhre 4. имеется 1 свободный байт. Его ис-
пользование для дополнительных сервисных
возможностей практически нереально. Зато
реально попробовать сделать печать файлов
не в три колонки, а в две, и тогда новые и
новые освободившиеся байты откроют вам
возможность ко всё новым и новым наворотам
в пределах всё того же одного сектора дис-
кового пространства.
Вообще,если всё же окажется, что мы дос-
таточно оптимизировали идею односекторных
boot'ов, и читателям не удастся выкроить
даже лишнего байта, то предлагаем устроить
конкурс на самый удобный и мощный семисек-
торный загрузчик. Такой boot очень удобен
тем, что может быть расположен в неис-
пользуемых секторах нулевого трека. В этом
случае получается, что boot не занимает
ни одного сектора на диске.
К тому же, если в одно/двух-секторных
boot-загрузчиках речь идёт только об обес-
печении минимального сервиса, то в boot'ах
длиной в семь секторов можно использовать
и автозачитывание дисков и красивые эффек-
ты на заднем плане (звезды,снег) и многое
другое.
Р.S. И главное, помните : "Любую процедуру
можно дооптимизировать до такой степени.
что она будет состоять из одной команды
NOP и при этом выполнять всё. что от неё
требуется".
Вот такая хорошая была статья..... Однако,
поскольку мы пубикуем её в электронном, а
не бумажном журнале, есть возможность
немного облегчить вам жизнь!
В приложении к журналу вы найдёте две го-
товых к употреблению версии "односектор-
ного" boot'а:
1SBOOT_М (версия by MAXSOFT)
и
1SBOOT_Р (версия by POLTERGEIST)
Версия от MAXSOFT'а была подробно описана
в прочитанной вами статье, а версия от
POLTERGEISTA примерно тоже самое, но с
другими функциональными особенностями. К
тому же эта версия появилась несколько
раньше и поэтому запрограммирована не-
много иначе. Как? Разберётесь сами, когда
дизассемблируете!
Ну а для самых пытливых умов, на диске
записанно два файла в формате редактора
ZX-WORD:
1S_boot+. (листинг с комментариями)
и
1S_boot-. (листинг без комментариев)
Первый файл удобен для конвертирования в
ассемблеры с редактором на 64 символа в
строке и с поддержкой русского шрифта по
альтернативной кодировке. Примером тако-
го ассемблера является версия ALASM4X8,
в то время как TASM х.хх хотя и поддер-
живает 64 символа в строку, но "обламы-
вается" на русских коментариях.
Для всех тех, кто пользуется не ALASM'ом,
предназначен второй листинг. В нём отсут-
ствуют комментарии на русском языке и дли-
на строки не превышает 42 символов.
Этот файл можно непосредственно грузить в
TASM 2.0, а с помощью опции Import
Tasm2.0 и в ассемблеры TASM 3.XX, TASM
4.0 (XLD), TASM 4.XX (RST#7).
Как конвертировать текст в другие типы
ассемблеров, я надеюсь, вы разберётесь
сами.
Удачи!
-════════════════════════════════════════-
* * * * *
MUSIC ВУ: VISUAL/MS/XTM
Other articles: