ZX-Ревю 1994 №2 1993 г.

Читатель- читателю - Бессистемные заметки на системные темы. Программистов часто делят на "системщиков" и "проблемщиков"


Темы статьи: Программирование  

БЕССИСТЕМНЫЕ ЗАМЕТКИ НА СИСТЕМНЫЕ ТЕМЫ

© Сергей Крушинский, 1994.

Программистов часто делят на "системщиков" и "проблемщиков". Первые расширяют возможности машины, вторые решают народно-хозяйственные задачи. Первые вырезают в скале дом при помощи напильника - то есть пытаются решать на Ассемблере глобальные задачи, вторые строят собачью конуру из железобетонных блоков -используют языки высокого уровня, где надо и где не надо. Еще бывают взломщики.

Одна из отличительных черт нашего "синклериста" - помимо тех, что были справедливо упомянуты в редакционном предисловии к моему очерку "SPECCY + АСТРОЛОГИЯ", № 9/10, 1993 - это то, что ему приходится сочетать в себе качества "системщика", "проблемщика" и "взломщика" одновременно - иначе со "Спектрумом" мало чего добьешься. Моей первоначальной задачей было написание астрологической программы. В ходе работы над программами "Protheus", "Sphera" и др., я столкнулся с проблемами, из-за которых пришлось лезть в дебри. А чем дальше в лес, тем больше дров!

"Горячие" клавиши.

Самый распространенный способ организации диалога программы с пользователем - это система разветвленных меню. Например, в меню - 1 предлагается: а), б), в).

Для а) предусматривается свое меню: а.а), а.б), а.в). И так далее. Такой подход универсален. Однако некоторые сервисные операции удобнее вызывать не из конкретного меню, а из любого места программы. Скажем, переключение клавиатуры из латиницы в кириллицу и обратно, вызов help^, копирование экрана на принтер, настройку каких-то параметров.

Во многих системах для этой цели предусмотрены так называемые функциональные клавиши. Расположены они в верхнем ряду и обозначены: F1, F2,...,F6. Бейсик компьютера MSX располагает командой ON KEY...GOSUB... Встретив строку ON KEY 1 GOSUB 300, интерпретатор будет знать: если пользователь нажмет клавишу F1, надо прервать программу, перейти к операторам, расположенным с указанной строки, а затем вернуться обратно.

В спектрумовском Бейсике ничего подобного нет, хотя 50 раз в секунду интерпретатор прерывает нормальный ход работы и проверяет, не нажата ли "BREAK". На Ассемблере организовать "горячие" клавиши несложно. Приведенный ниже фрагмент расположен с адреса 60199. Он состоит из двух частей: 1) инициализация прерываний IM2 и 2) обработка прерываний (с адреса 60208). Первую часть, длиной в 9 байтов, можно было бы расположить где угодно. Я предпочел вплотную присоединить ее к следующей. Вызывается она командой RANDOMIZE USR 60199. Ничего особенного не произойдет. Можно, как обычно, писать, отлаживать и запускать программы. Только теперь, если включить графический режим (Caps-Shift/9), машина как бы "зависнет" и будет "висеть" до тех пор, пока Вы не нажмете "1", "2", "3"..."5" - клавиши, к каждой из которых привязана написанная Вами процедура. Почему я сделал посредником графический режим вместо того, чтобы сразу опрашивать цифры? - В противном случае процедура годилась бы только на то, чтобы включить ее в работающие программы, да и то лишь в те, где не надо вводить числовые данные. Компьютер не стал бы спрашивать, с какой целью нажата, скажем, единица, а тупо перешел бы к соответствующей подпрограмме. А так можно и программировать. Только символы псевдографики придется вводить при помощи CHR$(), как в режиме KEYWORDS 1 Beta-Basic-a. Зато к "функциональным клавишам" можно присоединить такие полезные операции, как сохранение программы, перенумерация строк, переключение знакогенератора.

Листинг_1.

PORT1 EQU #FEFE ; Полуряд клавиатуры от CS до V

PORT2 EQU #EFFE ; Полуряд клавиатуры от 0 до 6

PORT EQU #F7FE ; Полуряд клавиатуры от 1 до 5

Обработка прерываний начинается с адр. #EB30 (60208) Это число содержится в ячейках ПЗУ 12543/12544, т.е. ячейка 12542 служит указателем. Для организации прерываний надо поместить в I число, равное (указатель-255)/256. Включаем прерывания 2-го типа.

60199

A, #30 I,A

ORG DI LD LD

2

IM EI RET

Теперь процедура обработки прерываний:

;Временное запрещ. прерываний во избежание ;Сохранение регистров ;для корректного возврата; ;вначале, пока программа не отлажена, ;лучше перестраховаться, ;заранее сохранив все.

аварии"

MAIN

DI

PUSH PUSH PUSH PUSH PUSH PUSH

HL DE BC AF IX IY

CALL

CHECK ;

К подпрограмме проверки клавиш.

Далее можно вызывать другие - например, часы.

POP

IY ;

Восстановление регистров.

POP

IX ;

POP

AF ;

POP

BC ;

POP

DE ;

POP

HL ;

JP

#0038 ;

Возврат с использованием процедур ПЗУ.

CHECK

LD

BC,PORT1

^ерва проверка, нажаты ли одновременно

СарБ-Shift/"9".

IN

A, (C)

Считаем байт из порта нижнего левого полуряда.

AND

%00000001

Выключаем все биты, кроме нулевого - он отвечает

за Caps-Shift.

LD

E,A ;

Временно сохраняем байт в регистре Е.

LD

BC,PORT2

Теперь то же для "9".

IN

A, (C)

Считаем байт из порта соответствующего полуряда.

AND

%00000010 ;

Маскируем все биты, кроме первого - "9".

OR

E ;

Сравниваем А и Е. Если в Е сброшен нулевой бит,

СР

0

а в А - первый, в регистре А остается нуль;

т.е. нажаты Caps Shift/"9".

RET

NZ

иначе - возврат.

KEYS

LD

BC,PORT3

Теперь надо ждать нажатия цифровой клавиши.

IN

A, (C)

BIT

0,A ;

Клавише "1" соответствует нулевой бит байта из

порта #F7FE.

JP

Z,KEY_1

Если он сброшен - переход

к пользовательской процедуре KEY_1.

BIT

1,A ;

Точно так же проверяем остальные 4 клавиши.

JP

Z,KEY_2

BIT

2,A ;

JP

Z,KEY_3

BIT

3,A ;

JP

Z,KEY_4

BIT

4,A ;

JP

Z,KEY_5

JR

KEYS ;

В противном случае - зацикливание.

KEY_1

...

;

Здесь может быть инструкция к Вашей программе

RET

;

возврат в MAIN.

KEY_2

...

;

А здесь - переключение знакогенератора.

RET

;

KEY_3

...

;

Можно также предусмотреть принудительное

;

выполнение команды STOP.

KEY_4

...

;

Или переход к заданной Бейсик-строке.

KEY_5 ... ;Копия экрана.

RET ;

. Мне кажется, процедуру KEYS хорошо было бы начать с печати меню в верхней или нижней строке

экрана:

<1> HELP <2> RUS/LAT <3> STOP и т.д. Только при печати лучше не связываться с ПЗУ. Как известно, при включенном режиме IM2 нельзя обращаться к TR-BOS. Если Вы планируете это сделать, временно перейдите на стандартные прерывания (для этого надо написать коротенькую процедуру, повторяющую 1 часть, только вместо команды IM 2 в соответствующем месте должна быть команда IM 1.

Русификация под EPSON. Когда я стал писать программы, выдающие текст по-русски и рассчитанные на широкий круг пользователей, оказалось, что одна из главных трудностей - это их адаптация к принтеру. Самый распространенный способ

русификации "Спектрума" - через настройку системной переменной CHARS на адрес набора русских символов, расположенных в порядке, который предписан стандартом KOH-7 - имеет ряд недостатков. Скажем, для сортировки символов нужна специальная подпрограмма-перекодировщик. Чтобы текст распечатывался на принтере, надо дать команду самому принтеру: "перейти на русский символьный набор". Если идет смешанный русско-латинский текст, то принтер приходится переключать постоянно. Ничего архисложного тут нет, беда лишь в том, что у разных принтеров разные команды. Да еще и с их интерфейсами царит полная неразбериха. К примеру, у меня к компьютеру присоединена микросхема интерфейса ZX-LPRINT III, а принтер MC-6312, EPSON - совместимый. Для того чтобы перейти в КОИ-7, надо дать команды: LPRINT CHR$ 1;"1"; CHR$ 14. Первые два кода уведомляют интерфейс, что последний код (14) - команда принтеру. Между прочим, из машинного кода это сделать не так просто, как кажется на первый взгляд. Спрашивается, откуда мне знать нюансы других интерфейсов и принтеров (тем более что о собственном-то я из-за недостатка справочной литературы знаю далеко не все?. Один из выходов - написать дополнительную программу для настройки принтера - как поступили авторы "ARTSTUDIO". К сожалению, и здесь всего не предусмотришь - как с тем же "ARTSTUDIO" не предусмотрели термоструйную печатающую головку.

Другой недостаток: пользователю не так-то просто во всем разобраться, если только он не программист-системщик. Собственно говоря, рядовой пользователь и не обязан знать подробности, которые потребует от него программа-настройщик. Скорее всего, он будет действовать методом тыка, раз за разом машина будет зависать; наконец, человек плюнет и, если рядом нет женщин и детей выскажет ряд "комплиментов" в адрес автора.

Согласитесь, не так уж много у нас программистов, которые могут решить эту задачу грамотно. Я не отношу себя к их числу и потому предлагаю поступать по-другому: использовать кодировку, получившую название "ГОСТ-альтернативная". В этом стандарте способен работать любой русифицированный EPSON-или IBM-совместимый принтер, начиная с упомянутого MC-6312. Коды от 64-го до 127-го - это обычная ASCII-таблица. Дальше идут русские буквы в алфавитном порядке и пустые ячейки, где можно разместить любые символы (аналог UDG). Последний код 239 - "я". (Напомню, что в ПЗУ "Спектрума" коды, начиная со 128го соответствуют символам псевдографики и ключевым словам Бейсика). Таким образом, вся таблица занимает 1664 байт (по 8 байтов на каждый символ).

В чем удобства? Во-первых, в последние годы EPSON приобрел репутацию стандарта. Принтеры этого типа распространились повсеместно. Нет ничего зазорного, если программист заявит, что его программа рассчитана на EPSON (попробуй он сказать, что на "Роботрон" - на смех поднимут!). Во-вторых, если это необходимо, принтер достаточно один раз в начале программы настроить на кодировку "ГОСТ-альтернативная" и забыть о нем. Можно не обременять этим программу - на принтере есть кнопка, которая служит для того же. В-третьих: никаких хлопот с сортировкой русских слов.

. Вначале надо создать, используя графический редактор, новую таблицу символов - латинских и русских, не помешают и символы графики - курсор, какие-нибудь галочки, крестики и т.п. (их коды: 176-223).

Затем - это, пожалуй, самое трудоемкое дело - придется написать собственную, привязанную к ПЗУ, процедуру экранной печати. Впрочем, примеры таких процедур не раз и не два приводились в публикациях "Инфоркома". Проще всего взять и переписать одну из них. Наконец, не помешает и собственная процедура ввода, учитывающая возможность работы с верхней частью символьной таблицы.

Так или иначе, большинство серьезных прикладных и игровых программ используют собственные процедуры ввода-вывода. Встречали ли Вы хоть раз "фирменную" игру, где ввод данных (например, Вашего имени) выглядел так же, как в стандартной команде IMPUT, привязанной к нижней строке экрана? Достаточно один раз отмучиться, написать процедуру ввода-вывода любой сложности, а потом использовать ее во всех программах. (Фирма Hisoft использует один и тот же редактор в Ассемблере, Паскале и Си). Можно обращаться к ним при обработке прерываний второго типа, не рискуя нарваться на неприятности, как бывает в случае с RST #10. Можно печатать не 32, а 64 символа в строке. Короче говоря, одним выстрелом убиваешь сразу нескольких зайцев.

Долой ЯВЕРТЫ - да здравствует ЙЦУКЕН!

Разумеется, для ввода символов "А"..."Я" ГОСТ-альтернативных, надо написать драйвер клавиатуры, иначе говоря, объяснить машине: "если включен русский режим и нажата клавиша "А", то печатай не символ с кодом 65, а символ с кодом 128". То же и для других клавиш. Спрашивается, как привязать к английским клавишам русские буквы? Многие синклеристы, среди них - авторы русифицированных версий текстовых редакторов "THE LAST WORD" и "TASWORD", предпочитают, чтобы наша "Р" соответствовала латинской "R', наша "Б" - латинской "B" и т.д. Таким образом, вместо английского "QWERTY" - "ЯВЕРТЫ". По-моему, это чистое недоразумение! Это совершенно не соответствует печатной машинке, а потому профессиональный секретарь, переводчик, журналист скорее вернется к ней, чем станет переучиваться. Нет, конечно, и я могу, скрепя сердце, набрать в редакторе "RUSTAS" имена и телефоны друзей. Но как бы я работал с текстами, если бы не обладал "THE LAST WORD''-ом, русифицированным под пишущую машинку фирмой "Кординал" - ума не приложу. Наверное, пришлось бы писать собственный редактор, а не заметки. Во всяком случае, если мы хотим, чтобы "Спектрум" использовался не только как детская игрушка, путь может быть только один - русификация под "ИЦУКЕН" (или "ЦУКЕНГ"). Как же добиться столь благородной цели?

. Предположим, у нас уже написана процедура, выполняющая сканирование клавиатуры и, в случае, если поступает печатный символ, возвращающая его код в переменной LETTER. Перед тем, как выдавать его на экран и помещать в INPUT-буффер, надо вызвать подпрограмму DECODE (перекодировка). При этом используется ячейка REGIME, которая содержит 0, если режим латинский и 1 - если русский.

Листинг_2.

A, (LETTER) 0 Z

DECODE

LD CP RET

если в LETTER - 0, немедленный возврат.

В родном алфавите больше букв, чем в английском, и некоторые символы не уместятся на нижних трех рядах - их придется привязать к значкам вроде доллара и "тюрьмы".

CP JP CP JP CP JP CP JP CP JP CP JP CP JP CP RET

Z,JAIL

Z,DOLLAR " % "

Z,PROCNT "&"

Z,AND_

Z,APOSTR

",ZKOB_1

","KOB_2

64

C

в остальных случаях если код < 64 - возврат. Цифры и знаки препинания незачем перекодировать.

SUB 63

LD B, A

LD HL,CODTAB-1

LOOK INC HL

DJNZ LOOK

LD A, (HL)

FOUND LD (LETTER),A RET

В таблице, расположенной с адреса CODTAB, даны коды, соответствующие кодам из нижней части ASCII. Первый - 158 "Ю", соответствует коду 64 "@", второй - 148 - коду латинской "А" и т.д.

Пропускаем нужное число байтов. Теперь HL указывает на нужный код,

который помещается в переменную LETTER вместо исходного. Можно выйти из "DECODE" и перейти к печати.

JAIL

LD

A,238

" ю"

вместо

"#"

JR

FOUND

DOLLAR

LD

A,149

;

вместо

JR

FOUND

PROCNT

LD

A,229

;

"x"

вместо

н о, i

0

JR

FOUND

AND_

LD

A, 157

;

"Э"

вместо

JR

FOUND

APOSTR

LD

A,237

;

"э"

вместо

", >

JR

FOUND

SKOB_1

LD

A, 134

;

"6"

вместо

JR

FOUND

SKOB_2

LD

A,166

;

" ж"

вместо

JR

FOUND

DEFB 0

CODTAB - с этого адреса начинается таблица:

158,148,136,145,130,147,128,143,144,152,142,139,132,156,146,153, 135,137,138,155,133,131,140,150,151,141,159,229,237,166,161,195, 129,228,168,225,162,227,160,175,224,2 32,174,171,164,236,226,233, 167,169,170,235,165,163,172,230,231,173,239,149,157,134,129,255

Переключаться из русского режима в латинский и наоборот можно либо из программы сканирования клавиатуры - так же, как проверяется CAPS-LOCK - либо при обработке прерываний. Допустим, поступил сигнал: изменить переменную REGIME. Следующая программка осуществляет это: RUSLAT LD HL,REGIME LD A, (HL) XOR 1 LD (HL) , A

RET

Простая картотека.

REGIME

TR-DOS - не идеальная операционная система, однако если уж она получила такое распространение у нас в стране, стоит использовать как можно больше ее возможностей. Например, файлы прямого и последовательного доступа.

Файл последовательного доступа - это почти то же самое, что список DATA, только хранится он не в программе, а на диске. Понятно, замена второго первым сокращает объем программы - от DATA вообще можно отказаться. Допустим, программа вычислила порядковый номер дня недели, N: 0 - Воскресенье, 1 - Понедельник и т.д. (о том, как это сделать, читайте в "SPECCY+АСТРОЛОГИЯ"). Дальше нужно найти в списке дней соответствующее название. Обычный способ: 10 RESTORE 50 20 FOR k=0 TO N 30 READ X$ 40 NEXT k

50 DATA "Воскресенье","Понедельник","Вторник","Среда","Четверг","Пятница", "Суббота" X$ - искомый день.

То же самое с использованием дисковой памяти:

10 RANDOMIZE USR 15619: REM: OPEN #5,"DAYS", R 20 FOR k=0 TO N 30 INPUT #5; X$ 40 NEXT k 50 CLOSE #5

Удобно хранить на диске значения констант или какие-нибудь параметры программы - особенно те, которые пользователь может менять и сохранять по своему усмотрению. Файлы последовательного доступа подобны одномерным массивам. Можно быстро считать или изменить любую запись, зная ее порядковый номер.

В астрологической программе "SPHERA" я организовал простенькую картотеку с данными на клиентов. Каждая запись содержит: имя, день, месяц, год рождения; географическую долготу и широту. Самая первая запись -общее число записей в файле. Их можно удалять, находить по заданному ключу (первая буква имени или первые несколько букв имени или имя целиком), добавлять. Понимаю, что это самая примитивная из возможных катотек, но в моем частном случае ее вполне хватило на то, чтобы обеспечить обмен данными между основной программой и диском. Вот вкратце механизм работы.

1. Поиск Записей по Заданному ключу. Открыть файл F$. ОТ - номер канала, LENGTH - длина записи: RANDOMIZE USR 15619: REM :OPEN #CH,F$ RND ,LENGTH

Положить найденный стринг X$="",FOUND (НАИДЕН) + 0 (ЛОЖЬ) Запросить и ввести ключ, Y$.

Считать первую запись - указатель общего числа записей в файле, MAX: INPUT #CH;(0),A$: LET MAX=VAL A$

Просмотреть число записей, равное МАХ, в поисках записей, чье первое поле совпадает с ключом Y$. Если такие записи найдены, выдать их на экран вместе с номерами; присвоить флагу FOUND значение "ИСТИНА" (1):

FOR L=1 TO MAX INPUT #CH;(L),A$

IF A$(TO LEN Y$)=Y$ THEN PRINT A$: LET FOUND=1 NEXT L

Если не найдена ни одна запись, сообщить эту печальную новость, а затем предложить либо ввести новый ключ и начать поиск заново, либо выйти из программы в этом случае переход к последнему шагу.

Если хоть одна запись найдена (FOUND=1), предложить следующее: удалить запись; изменить ее; передать основной программе. Запросить номер записи с которой производится та или иная операция. Выполнить соответствующую подпрограмму.

Пример: в качестве ключа задана буква "Л". На экране появятся: 1. Лена

12. Лева

43. Леший

Хочется избавиться от Лешего. Даем команду "удалить" и на запрос "номер?" набираем: "43" (или подводим курсор к третьей строке и нажимаем ENTER, или, ловко орудуя "мышкой". впрочем, не стоит вдаваться в подробности!).

Закрыть файл:

RANDOMISE USR 15619: REM: CLOSE #CH Выйти.

2. Удаление Записи.

Допустим номер записи N=12. Надо уменьшить указатель MAX на единицу и переписать его на диск:

LET MAX=MAX-1

LET Z$=STRING(LENGTH,"0")

прошу прощения, но для краткости привожу функцию Beta-Basic-a. Поскольку каждая запись - строка, длина которой = LENGTH, a MAX мы получаем, преобразуя строку в число функцией VAL, в незанятых ячейках должен быть "0".

LET A$=Z$(TO LENGTH - LEN STR$ MAX) + STR$ MAX PRINT #CH;(0),A$

таким образом, если LENGTH=10, a MAX=12, нулевая запись будет выглядеть так: "0000000012" Затем организуется цикл; сдвигающий записи влево:

FOR I=N+1 TO MAX INPUT #CH;(I),A$ PRINT #CH;(I-1),A$ NEXT I RETURN

3. Пополнение списка строкой Y$.

Программа просматривает все записи. Если в списке нет ни одной, чье имя (первое поле) совпадает с именем, которое надо добавить, MAX увеличивается на 1 и строка записывается в конец:

PRINT #CH;(MAX),Y$

В противном случае - запрос: "переписать/выйти". При ответе "переписать", новая запись заменяет старую. ."Играя" с переменными MAX, LENGTH и прочими, легко создать и другие полезные для картотеки функции. Разумеется, приличная база должна уметь сортировать данные, причем не только по первому, а по любому полю - во-первых, для наглядности, во-вторых, для ускорения поиска. Начинать лучше не с поиска, а с просмотра, желательно использовать многооконный интерфейс и бегающий курсор. Кстати, все это есть в картотеке, которая прилагается к операционной системе IS-DOS. Но моей задачей было не соревноваться с такими "монстрами" как MASTERFILE или IS-DOS, а обеспечить свою программу минимальным сервисом.

УНИВЕРСАЛЬНЫЙ ЗАГРУЗЧИК

Мы уже касались в "РЕВЮ" направления, связанного с разработкой загрузчиков программ, которые не требуют никакой адаптации при переносе с магнитофона на диск. Такие программы одинаково хорошо загружаются как с магнитофона, так и с диска. Универсальные загрузчики на уровне Бейсика были предложены Андреем Алексеевым в статьях "WHAM THE MUSIC BOX" (РЕВЮ-93 № 11-12 и РЕВЮ-94 № 1). Сегодня, возвращаясь к этой теме, предлагаем вниманию читателей другой универсальный загрузчик. Свой вариант предлагает Романенко С.Н. из г. Днепропетровск. Загрузчик содержит фрагмент в машинном коде:

3A535C

LD

A, (23635)

FE3B

CP

59

CA033D

JP

Z,15619

3A5D5C

LD

A, (23645)

C602

ADD

A,2

325D5C

LD

(23645),A

3E6F

LD

A,111

32BB5C

LD

(23739),A

C9

RET

Если расположить коды в начальной строке программы, сразу за оператором REM, то запускается этот блок из Бейсика например так:

1 REM к о д ы (22 байта)

10 RANDOMIZE USR (PEEK 2 3 635+2 5 6*PEEK 23636+5): REM : LOAD "program"CODE

Работает блок кодов не просто, а очень просто. Сначала проверяется системная переменная PROG. Если младший байт равен 59, то есть (PROG)=23867=59+256*93), то значит, подключен БЕТА-диск. В этом случае происходит переход на адрес 15619 - происходит загрузка с диска. Иначе, если PROG не изменено, то в аккумулятор загружается число из ячейки 23645. После увеличения его на два байта (двоеточие и оператор REM), управление будет передано оператору LOAD "program"CODE. Затем в ячейку 23739 заносится число 111 для того, чтобы при загрузке с ленты на экран не выводились названия файлов. После этого - возврат в Бейсик.

Нам очень понравилась идея, заложенная в этом методе. Однако при тестировании загрузчика были выявлены и его "узкие" места. Поэтому добавим несколько слов от себя.

Во-первых, о ячейке 23645. По этому адресу в таблице системных переменных находится переменная CH_ADD - адрес следующего интерпретируемого символа. Величина эта - двухбайтная. Правда, увеличить ее требуется при загрузке с магнитофона всего на два байта, так что скорее всего, увеличив младший байт на два, мы получим верный результат. Но не исключен случай, когда младший байт равен, например, FEH (254) или FFH (255). В этом случае при увеличении на два содержимого аккумулятора мы получим неверный результат, так как не учитывается старший байт CH_ADD. Поэтому правильнее будет величину CH_ADD загружать в двухбайтный регистр, скажем, HL, и его увеличивать на два.

Другой момент. Системная переменная PROG в случае дискового варианта не всегда равна 23867. Обладатели прошивки "Турбо-90" могут проделать простой эксперимент. Если после инициализации интерфейса БЕТА-диска Вы сделаете PRINT PEEK 23635+256*PEEK 23636, то естественно, получите 23867. Теперь войдите в монитор командой "*", затем вернитесь в Бейсик (S.SH+8). Теперь выполните RANDOMIZE USR 15616. Обратите внимание, что при выходе в TR-DOS появилось фирменное сообщение, что происходит при работе только при инициализации TR-DOS (то есть, когда область Бейсика отодвигается на 112 байт и формируются системные переменные TR-DOS. Теперь опять выполните PRINT PEEK 23635+256*PEEK 23636. Теперь значение PROG изменилось, оно равно 23979 -увеличилось на 112 байт за счет смещения области Бейсика.

В такой ситуации кодовый блок универсального загрузчика передаст управление на загрузку с магнитофона. Чтобы загрузчик работал правильно, можно несколько изменить логику перехода. Переходить на загрузку с диска не в том случае, если (PROG)=23867, а в том случае, если (PROG) не равно 23755 (когда БЕТА-диск не инициализирован).

Усовершенствованный вариант кодового блока загрузчика выглядит так (кстати, длина его не изменилась):

5D4 0

3A535C

LD

A,(#5C53)

5D43

FECB

CP

#CB

5D45

C2033D

JP

nz ,#3d03

5D4 8

2A5D5C

LD

HL,(#5C5D)

5D4B

23

INC

HL

5D4C

23

INC

HL

5D4D

225D5C

LD

(#5C5D),HL

5D50

3E6F

LD

A, # 6F

5D52

32BB5C

LD

(#5CBB),A

5D55

C9

RET

Десятичный

дамп блока кодов:

58,83,92,254,203,194,3,61,42,93,92,35,35,34,93,92,62,111,50,187,92,201 И еще об одной тонкости в работе этого оригинального загрузчика.

Аварийная ситуация может возникнуть, если Вам понадобится загрузить кодовый блок под принудительный адрес (например, блок кодов-экран после редактирования в "ARTSTUDIO" будет иметь адрес 24320, и загружать его нужно командой LOAD "name"CODE 16384). Ошибочной в этом случае будет такая команда загрузки: 20 RANDOMIZE USR (PEEK 2 3 635+2 5 6*PEEK 23636+5): REM: LOAD "name" CODE 16384

Дело в том, что при загрузке с диска все будет в порядке, но при загрузке с магнитофона интерпретатор Бейсика следом за числом 16384 будет искать код 14 (число) и следом за ним само число в пятибайтной форме. В Бейсик-строке, которая приведена выше нет ни кода 14 ни самого числа, так как все, что набрано в строке 20 после оператора REM - вводится как чистый текст.

Выход из этого затруднительного положения не простой, а очень простой. Вместо 16384 пишите: VAL "16384". И конечно же, Вы понимаете, что из-за TR-DOS недопустимо выражение: LOAD "name" SCREENS. Кроме того в одной Бейсик-строке может находиться только команда загрузки одного файла.

В заключение говорим большое спасибо, Романенко С.Н. за свежую идею.

Приятно, что в нашей почте все чаще начинают появляться письма по поводу дисковой операционной системы TR-DOS. Мы можем порадовать наших читателей письмом Цыгулина Алексея из г. Новосибирска, в котором он приводит более полный список системных переменных, чем был в РЕВЮ-93 № 1-2.

Таблица системных переменных TR-DOS.

#адрес

адрес

длина

комментарий

5CB6

23734

1x

Используется, если есть INTERFACE 1 (если значение равно #F4), то область

переменных не переносится; если равно #00, то проверяется 23832.

5CC2

23746

1x

Содержит #С9; используется системой TR-DOS для вызова подпрограмм из SOS.

5CC8

23752

1

Код, определяющий режим работы дисковода А:

бит 7 = 0 - дисковод 40-дорожечный

бит 7 = 1 - дисковод 80-дорожечный

бит 1 = 1 - дисковод двухсторонний

бит 0 = 0 - использовать 80-дорожечный дисковод, как 40-дорожечный.

5CC9

23753

1

То же для дисковода B:

5CCA

23754

1

То же для дисковода C:

5CCB

23755

1

То же для дисковода D:

5CCC

23756

1x

Текущий сектор при чтении каталога.

5CCD

23757

1x

#80 - готовность дисковода.

5CCE

23758

1x

#00 - чтение сектора; #FF - запись.

5CD6

23766

1x

При #FF - команда не выполнена.

5CD7

23767

2x

Промежуточный старт (тип В и С) после проверки типа дисковода содержит число

дорожек.

5CD9

23769

2x

Внутренний аналог CH ADD, промежуточная длина (тип В и С).

5CDB

23771

2x

Промежуточная длина программы.

5CDD

23773

8

Имя файла в ASCII.

5CE5

23781

1

Тип файла.

5CE6

23782

2

При типе С - стартовый адрес; при типе В - длина Бейсик-программы.

5CE8

23784

2

Длина файла.

5CEA

23786

1

Объем файла в секторах.

5CEB

23787

1

Номер первого сектора файла (0-15).

5CEC

23788

1

Номер первого трека файла.

5CEF

23791

1x

1 - если есть INTERFACE 1.

5CF4

23796

1x

Текущий номер сектора.

5CF5

23797

1x

Текущий номер трека.

5CF6

23798

1

Дисковод для временной операции (0-3).

5CF7

23799

2

При возврате из 15616 - обнуляется.

5CF8

23800

1

Дисковод при операции с двумя файлами #FF, если канал открыт.

5CF9

23801

1

Дисковод при операции с двумя файлами признак операции READ/VERIFY номер

дисковода (при команде #07).

5CFA

23802

1

Время перемещения головки дисковода А:

5CFB

23803

1

Время перемещения головки дисковода В:

5CFC

23804

1

Время перемещения головки дисковода С:

5CFD

23805

1

Время перемещения головки дисковода D:

5CFE

23806

1x

Код команды для 1818ВГ93.

5CFF

23807

1x

Номер сектора для подпрогр. чтение/запись сектора.

5D00

23808

2x

Текущий адрес буфера (#05/#06).

5D02

23810

2x

Сохраняет HL для внутренних нужд.

5D04

23812

2x

Сохраняет DE для внутренних нужд.

5D06

23814

1

Количество знаков при поиске имени файла (для команды #01). Начальное значение #09

5D07

23815

1x

#09.

Счетчик удаленных файлов (для команды #12).

5D08

23816

1x

Первый символ имени файла (для команды #12).

5D0C

23820

1x

Флаг состояния рабочего буфера TR-DOS (257 байт с адреса 23846) #FF - буфер

отсутствует; #00 - буфер существует.

5D0E

23822

1x

Флаг принадлежности команды #FF - работает Бейсик; иначе - TR-DOS.

5D0F

23823

1x

Код ошибки TR-DOS; внутри TR-DOS, при неравенстве нулю вводит команду

RETURN, иначе пустую строку (подпрограмма #20EF).

5D10

23824

1x

Старший байт ошибки, при вызове 15616 обнуляется; при вызове 15635 необходимо

обнулять принудительно во избежание ошибочных ситуаций.

5D11

23825

2x

Адрес строки команды для TR-DOS при вызове 15616 повторяет E LINE (23641) при

вызове 15619 повторяет CH ADD (23645).

5D13

23827

2x

Копия ERR SP при равенстве старшего байта #АА автоматически выполняется

команда RUN "boot", а в 23833 код #FE.

5D15

23829

1x

При равенстве #00 печатает сообщение TR-DOS, иначе - не печатает.

5D16

23830

1

Копия системного регистра (555ТМ9).

5D17

23831

1

При неравенстве #АА, при вызове 15616 рисуется заставка, при равенстве #FF не

попадает на ошибку при чтении неверного адресного маркера.

5D18

23832

1x

Используется при подключении INTERFACE 1 (если значение равно #FF, то

меняются местами блоки в памяти по адресам 23747-23859 объемом 45, при вызове

TR-DOS заносится #FF).

5D19

23833

1

Дисковод по умолчанию.

5D1A

23834

2x

Внутренний адрес процедуры завершения (201).

5D1C

23836

2x

Сохраняет SP.

5D1E

23838

1

Номер файла, если он найден (команда #0А).

5D20

23840

3

Первые три символа введенной строки.

Символом "x" отмечены переменные TR-DOS, которые не рекомендуется изменять, т.к. это может привести к нарушению работы системы.

Алексей уточняет, что команда #17 (для регистра С) означает "выбрать нижнюю сторону", а #18 "настройка на диск".

Наш корреспондент также сообщает о некоторых особенностях работы TR-DOS.

"Вот что я заметил. Если при работе команды MOVE нажать BREAK, или произойдет какой-либо сбой), то на диске образуются потерянные сектора (что-то вроде потерянных кластеров в IBM-PC) и TR-DOS их не видит. Можете подсчитать количество свободных секторов плюс сумму длин файлов - она будет меньше положенного! Найти "дырку" можно при помощи простой программы вроде DIR (см. РЕВЮ-93, № 1-2, стр. 26). Если удалить все файлы после "дырки", то она исчезает. Именно из-за этого может не сработать команда "OPEN" (тот же РЕВЮ, стр.27), так как при существовании "дырок" (а их можно сделать специально), расстояние между файлами будет равно длине файла плюс длина "дырки", а это совсем не то, что надо! Так что лучше изменить программу "OPEN": удалить строки 1050-1070, а 1080 оставить, но без IF, то есть: 1080 LET lens=PEEK (a+12)+PEEK (a+11)<>0)

При этом "дырки" останутся, но не будут включены в файл.

Дырки, по-видимому, образуются из-за того, что вначале переносится исходный заголовок, потом файл, а затем заголовок изменяется на новый и переписывается.

ИФК: Добавим несколько слов от себя. При создании программы "OPEN", о которой упоминает Алексей, в первую очередь встал вопрос о том, на основании чего рассчитывать длину файла в секторах? Варианта два. Первый -длину файла рассчитывать исходя из его длины в байтах (целое число секторов плюс один, как это делается в строке 1080). Второй вариант разность между началом выбранного файла и началом следующего. Однако первый вариант может тоже дать ошибочные данные. Речь идет вот о чем. Вы, наверное, не раз обращали внимание, что встречаются программы, состоящие из одного Бейсик-файла (в последнее время все чаще). Если Вы обратите внимание на длину Бейсик-файла в байтах, то увидите что-то порядка 100-200 байт, значит должен быть занят 1 сектор. В заголовке же Вы видите, к примеру, 120 секторов. В программе применен специальный способ загрузки (о котором речь еще пойдет ниже). Коды грузятся в память начиная с того трека и сектора, где было закончено чтение Бейсик-загрузчика. Грузится заданное число секторов в заданную область, параметры определяются загрузчиком в машинных кодах, спрятанным в Бейсик-программе. Сам кодовый блок программы расположен сразу же за Бейсик-загрузчиком как раз в "дырке", искусственно созданной. Если это не последний файл на дискете, то обработка дискеты программой "OPEN" с изменениями, предложенными Алексеем, приведут к тому, что обрабатываемый файл станет длиной 1 сектор. Остальное место придется на "дырку", в которой находятся коды. Теперь Вы не сможете переписать такую программу на другую дискету, так как перепишется только 1 сектор.

Поэтому, длина файла в секторах в программе "OPEN" рассчитывается вторым способом для всех файлов, кроме последнего, для которого неопределенно понятие: "начало следующего файла". Естественно, он же последний. Так что его длина в секторах рассчитывается первым способом, однако есть риск, что последний файл как раз

окажется с измененной длиной (в секторах). Истиную длину в этом случае можно определить только "раскрутив" Бейсик-загрузчик и просмотрев параметры машиннокодовых команд загрузки.

А теперь перейдем к следующему письму. Его прислал Фомин Илья из г. С-Петербурга.

Скорость загрузки программ с диска можно заметно увеличить за счет исключения периодического обращения к нулевой дорожке, которое происходит при чтении очередного файла программы. Выигрыш во времени будет тем больше, чем больше файлов необходимо программе и чем дальше она находится от начала диска. Все это достигается за счет замены Бейсик-загрузчика - загрузчиком в кодах, который использует точку входа в TR-DOS с адресом #3D13 (15635). При этом необходимо подготовить исходные данные в регистрах: LD B,число загруж. секторов. LD C,#05

LD DE,(23796) -текущие дорожка/сектор (см. Таблицу системных переменных TR-DOS). LD HL,адрес загрузки. CALL #3D13

Количество секторов и адрес загрузки каждого кодового файла Вам даст команда LIST. Разумеется, если в Бейсик-загрузчике задан принудительный адрес загрузки кодового файла (например, загрузка файла-картинки в адрес 16384), то необходимо задавать именно его. При создании кодового загрузчика надо повторить приведенную выше процедуру для каждого загружаемого файла программы, добавить в конце в зависимости от конкретных обстоятельств либо RET, либо JP START ADR. Поместите полученный машинный код любым привычным для Вас способом в Бейсик (например, в начальную строку после REM) и сохраните полученный загрузчик на ленте. Выглядеть он будет примерно так:

0 REM ... здесь находятся коды

1 CLEAR 24 999: INK NOT PI: PAPER NOT PI: BORDER NOT PI: CLS: RANDOMIZE USR 23872

Затем, сразу же после загрузчика запишите на диск файлы, необходимые программе, в том же порядке, как это указано в загрузчике. Теперь можете удалить кодовые файлы, запомнив их суммарную длину (при удалении файла удаляется только заголовок файла, а сами коды на диске - не затрагиваются). После этого любым DISK-DOCTOR-ом исправьте длину загрузчика в секторах на величину, равную суммарной длине всех файлов (включая сам загрузчик). Вот и все! Перепишите получившийся Бейсик-файл на другую дискету, и Вы увидите, что он, несмотря на видимое отсутствие кодовых файлов, прекрасно работает, и при этом не обращается к нулевой дорожке.

ИФК: в этом способе как раз применяется способ хранения кодовых блоков в "дырке", о чем говорилось в предыдущем материале. Чтобы избежать конфликтов с файловой структурой, Вы можете не удалять кодовые файлы и не изменять длину в секторах Бейсик-загрузчика DISK-DOCTOR-ом. Можете оставить все файлы, как они есть. Хотя можете как угодно изменить их имена и адреса загрузки (например, обнулить адреса при помощи того же DISK-DOCTOR-а). Загрузка все равно будет выполняться при помощи потрекового чтения, без обращения к нулевой дорожке. Зато полностью сохраняется файловая структура TR-DOS. В любом случае, как поступить - решит для себя каждый сам, в зависимости от того, что нужно: сделать так, чтобы все было максимально "ясно и прозрачно" или сделать так, чтобы нежелательные "хаккеры" подольше поломали себе головы.

Илья приводит еще несколько соображений по защите программ от копирования с помощью кнопки "MAGIC": "При своей работе она изменяет системную ячейку, используемую для сканирования клавиатуры (#5С10), занося туда код 201 (RET). Организовав циклический опрос этой ячейки (например, в подпрограмме опроса клавиатуры), Вы сможете сразу же установить факт нажатия "MAGIC" и принять соответствующие меры. Этот способ, кстати, использован в программе "DCU 2".

Другим способом защиты может быть использование того факта, что "MAGIC" в момент нажатия заносит большое количество данных на стек. Здесь способов защиты может быть много, например, разместить стек в верхней части экрана. Тогда при работе "MAGIC" непомерно "разбухший" стек частично "залезет" в ПЗУ и по окончании работы "MAGIC" в него будут сняты совсем не те данные, какие были в него занесены.

Существует еще один способ непосредственное программирование ВГ-93. Этот способ наиболее эффективен, так как "MAGIC", после некоторого "раздумья" просто испортит Ваш диск. К сожалению, текст этой процедуры я привести не могу, так как загрузчик, где она находится, очень мощно закрыт от просмотра с помощью циклической защиты типа "ксорка", которая содержит множество вложенных недокументированных команд, второго режима прерывания и т.д. Однако я не прекращаю своих попыток, есть уже некоторые успехи, и я думаю, что скоро я смогу порадовать читателей РЕВЮ".

* * *




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



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

Похожие статьи:
Немного изврата - считалки "Игры с оружием".
Интервью - Интервью Капитана Nemo с комментариями фирмы Искрасофт.
b0nus pAck - body #20.zip
Розыгрыши - как разыграть ваших друзей и подруг.
Железяки - загрузка программ в спектрум с CD с использованием SP-Dif.

В этот день...   25 апреля