Глава
5
КАК БОРОТЬСЯ С RAMTOP'OM
Часто
спрашивают: «Как переделать программу на диск, если граница RAMTOP установлена
слишком низко и не позволяет нормально работать с системой TR-DOS?». Попытаюсь
ответить на этот вопрос.
В
одной из предыдущих глав предлагался способ экономии памяти посредством
разбиения загрузчиков на несколько частей. Однако такой способ является далеко
не самым изящным, да и помогает не всегда. Сложности начинаются уже тогда,
когда RAMTOP опускается до адреса 24500. На всякий случай напомню, что RAMTOP —
это не фамилия, это адрес последней ячейки памяти, используемой Бейсиком.
Устанавливается RAMTOP оператором CLEAR <адрес>.
При
попытке переделать на диск программу с наипростейшим загрузчиком
10 BORDER 1: PAPER 1: INK 1: CLS
20 CLEAR 24199
30 LOAD ""CODE
40 RANDOMIZE USR 49152
проблемы
начинаются уже в тот момент, когда Вы успешно вывалились в Бейсик по Break
и пытаетесь выйти в TR-DOS с помощью оператора RANDOMIZE USR 15616.
Лаконичное сообщение Out of memory не упустит шанса появиться на экране.
Вероятно, после нескольких попыток Вы решите, что эту программу гораздо приятней
загружать с кассеты или «скинуть» @безьяньей кнопкой.
Мне
рассказывали, как горе-программисты меняют CLEAR 24000 на CLEAR 25000,
записывают программу таким образом, и она у них даже как-то работает. Я же Вам
скажу следующее: этого делать нельзя ни в коем случае. Если Вы полтора миллиона
раз подряд сбросите программу @безьяной, то, скорее всего, навредите ей меньше, чем подобной заменой.
Давайте
лучше подумаем, как решить эту задачу более изящным способом. Вы не хуже меня
понимаете, что если системе TR-DOS не хватает рабочего места, это место нужно
освободить. А именно, необходимо поднять RAMTOP примерно до адреса 24700 или
выше, то есть спрятать куда-нибудь примерно 500—700 байт. Здесь, в зависимости от
длины и расположения файлов программы, могут возникнуть две ситуации. Первая —
кодовый файл программы достаточно короткий, вторая — кодовый файл длинный и
занимает всю или почти всю память, начиная от RAMTOP и до самого верха (до
адреса 65535).
Сначала
рассмотрим более простой — первый случай.
Предположим,
что кодовый файл, для которого необходимо написать загрузчик с диска, имеет
адрес начала 24200 и длину 40800, а загружается с ленты и запускается
приведенным выше загрузчиком. Если подсчитать, то получится, что адрес
последнего занимаемого файлом байта равен 64999, а 536 байт с адреса 65000
фактически остаются свободными*. Итак, установив этот факт, Вы обзовете идиотом
того, кто поместил файл именно в эти адреса, в результате чего 536 байт вверху
пропадают, а внизу так тесно, что ощущаешь себя пассажиром троллейбуса в час
пик (или скорее потенциальным пассажиром, безуспешно пытающимся залезть в
переполненный троллейбус). Надо заметить, что обзывать никого не стоит, поскольку
у автора программы могли быть веские причины на то, чтобы поместить ее именно
туда, куда он ее поместил. Кроме того, автор, вероятно, не предполагал, что
кому-то приспичит переделывать его программу на диск да к тому же в системе
TR-DOS.
Первое,
что приходит на ум, — это загрузить файл чуть выше (в данном случае логично
использовать все 536 байт), а затем, когда обращений к диску уже не будет (то
есть системе теперь не понадобится память под буферы и т. п.), поставить файл
на место и запустить. Все, казалось бы, проще простого, и не исключено, что Вы поспешили
написать на Бейсике нечто вроде
FOR n=24736 ТО 65535: POKE n-536,PEEK n: NEXT n
Если у Вас хватило терпения дождаться результатов работы этой маленькой,
но гаденькой программки, то Вы, вероятно, убедились, что она честно выполняет
свое дело, но запускать ее нужно вечером, а утром, почистив зубы, можно будет
поиграть в игрушку, которая наконец заняла свое привычное место и запустилась.
Я не
предлагаю отказаться от этого метода, поскольку он действительно наиболее прост
и удобен, я предлагаю небольшую подпрограмму на ассемблере, которая поможет
переместить нужный кусок памяти на другое место за несколько более короткое
время:
33,SL,SH LD HL,SOURCE
17,TL,TH LD DE,TARGET
1,LL,LH LD BC,LENGTH
195,195,51
JP 13251(или просто LDIR)
— где SOURCE
— адрес настоящего местоположения файла; TARGET — адрес желаемого
местоположения файла; LENGTH — его длина. В нашем случае значения будут
равны, соответственно, 24736, 24200 и 40800.
___________________________________________________________________
*
Если не верите — можете посчитать на пальцах; кстати, Вы зря смеетесь: если
использовать двоичную систему счисления, то на пальцах без особых ухищрений
можно показать число в диапазоне от 0 до 1023, а если прибавить еще шесть
спичек, то вся память Speccy будет у Вас как на ладони.
Если
Вы не знаете толком, что такое ассемблер и кому в голову взбрело его изобрести,
то Вас больше заинтересует левое поле. Это коды приведенных мнемоник в
десятичной системе счисления. Загадочные SL, SH, TL, TH, LL и LH означают
старшие (Н) и младшие (L) байты двухбайтовых чисел. Как известно, байт может
принимать значения от О до 255, поэтому для размещения в памяти числа 24736 необходимы
как минимум два байта. Младший байт для SOURCE вычисляется как
LET SL=SOURCE-256*INT (SOURCE/256)
— старший как
LET SH=INT (SOURCE/256)
Остальные
числа рассчитываются аналогичным способом. Для получения значений байтов можно
применить и другой, более интересный приемчик:
RANDOMIZE SOURCE: LET SL=PEEK 23670:
LET SH=PEEK 23671
Итак,
скрупулезно разложив все исходные данные на отдельные байты, Вы получили некий
набор чисел. Для уверенности можете проверить правильность проведенных
операций:
LET SOURCE=SL+256*SH
Набор
чисел в нашем примере будет выглядеть так:
33,160,96
17,136,94
1,96,159 195,195,51
Теперь
Вы спросите, что же с ними делать. Числа можно приписать к началу Вашего файла
(он, таким образом, станет на 12 байт длиннее) и сохранить его в новом виде.
Ввести числа в память можно, непосредственно выполняя операторы РОКЕ один за
другим:
РОКЕ 24724,33
РОКЕ 24725,160
РОКЕ 24726,96
и.т.д., либо
написав несколько строк На Бейсике;
10 FOR п=24724 ТО 24735
20 READ s
30 POKE n,s
40 NEXT n
50 DATA 33,160,96,17,196,94,1,96,159,195,195,51
Имеется
в виду, что файл уже загружен в память на 536 байт выше (например, оператором
LOAD "name"CODE 24736).
Подготовив
файл таким образом, запишите его на диск:
SAVE "name"CODE 24724,40812
и напишите
загрузчик с диска:
10 BORDER 1: PAPER 1: INK 1
20 CLEAR 24723
30 RANDOMIZE USR 15619: REM : LOAD"name"CODE
40 CLEAR 24199
50 RANDOMIZE USR 24724
60 RANDOMIZE USR 49152
Обратите
внимание, что первый CLEAR устанавливает RAMTOP на единицу меньше, чем
адрес загрузки файла, затем, после загрузки файла, устанавливается
«оригинальный» RAMTOP и выполняется написанный нами фрагмент в машинных кодах
(строка 50), который и помещает файл на нужное место. Затем программа нормально
запускается (строка 60).
Если
в той программе, которую Вы захотите адаптировать, адрес загрузки файла
примерно такой же, как в приведенном примере, то проблем возникать не должно.
Однако нередки ситуации, когда граница RAMTOP, которую устанавливает загрузчик,
настолько низка, что при попытке выполнения второго оператора CLEAR, Вы
получите уже знакомое сообщение об ошибке: 4 Out of memory, 40:1. Такая
ситуация может возникнуть в связи с тем, что, как уже говорилось, TR-DOS резервирует
под свои системные переменные 112 байт.
С
этим бороться несколько сложнее, однако тоже можно. Ниже приводится программа в
кодах, которая поможет решить эту проблему. Необходимо заметить, что работать
она будет только в том случае, если адаптируемая программа запускается единожды
и в Бейсик больше не возвращается.
49,CL,CH LD SP,STACK
33,EL,EH LD HL,ENTRY
229 PUSH HL
33,SL,SH
LD HL,SOURCE
17,TL,TH LD DE,TARGET
1,LL,LH LD BC,LENGTH
195,195,51 JP 13251
— где STACK
— адрес размещения машинного стека (для решаемых нами задач он должен совпадать
с параметром оператора CLEAR); ENTRY — входная точка программы
(то есть число, которое следовало за оператором RANDOMIZE USR в
исходном загрузчике). В нашем примере STACK будет равен 24199, a ENTRY
— 49152.
Если
эту подпрограмму добавить к основному файлу так же, как я описывал, то
загрузчик на Бейсике будет выглядеть следующим образом:
10 BORDER 1: PAPER 1: INK 1
20 CLEAR 24716
30 RANDOMIZE USR 15619: REM : LOAD "name"CODE
40 RANDOMIZE USR 24716
Обратите
внимание, что в новом загрузчике, в отличие от предыдущего, нет ни оператора CLEAR
24199, ни RANDOMIZE USR 49152, эти операции выполняются приведенной
подпрограммой в машинных кодах.
Сразу
хочу предупредить, что вполне возможно возникновение различных нюансов, и Ваша
программа все-таки не заработает. Это может произойти из-за того, что программа
после выполнения каких либо операций все же возвращается в Бейсик и продолжает
в нем работать. Это может привести к самым разнообразным эффектам, однако
подобные ситуации встречаются достаточно редко.
________________________
С
этими довольно простыми случаями Вы, вероятно, уже разобрались (иначе — читайте
все с начала; если и это не поможет — обзовите автора неприличным словом как
несостоявшегося).
Теперь
разберем более сложную и неприятную ситуацию, когда, после тщательных расчетов
(быть может, на пальцах), Вы пришли к прискорбному выводу, что файл занимает
всю память от RAMTOP и выше, а так необходимые 500—700 байт взять совершенно
негде. Не пугайтесь, это еще не повод для беспокойства. Вы забыли о довольно большом
резерве — видеопамяти и буфере принтера. Использование буфера принтера предпочтительнее,
но он имеет объем лишь 256 байт (с адреса 23296), поэтому может помочь только,
если недостает каких-нибудь 200-250 байт.
По
большому счету, в случае длинного файла (имеется в виду файл, занимающий все
пространство от RAMTOP и выше) организация загрузки и запуска будет во многом
аналогична организации загрузки и запуска короткого файла. Единственным
принципиальным отличием будет то, что длинный файл придется разбить на два коротких.
Способов разбиения файлов на куски существует достаточно много. Это можно
сделать и непосредственно на диске, с помощью программы Disk Doctor*.
Подробнее
рассмотрим ситуацию, когда исходный файл находится еще на кассете. Самое
простое — загрузить файл в память, не забыв установить правильный
(оригинальный) RAMTOP, и записать два файла на кассету оператором SAVE.
При этом имейте в виду, что выходить в TR-DOS ни до, ни после загрузки файла ни
в коем случае нельзя.
Предположим,
Вы захотели адаптировать программу со следующими исходными данными:
загрузчик:
10 CLEAR 23999: LOAD ""CODE
20 RANDOMIZE USR 24000
файл: адрес загрузки
— 24000, длина — 41536.
Сбросьте
машину (аккуратно, так, чтобы телевизионный кабель не оборвался), затем
проделайте следующие операции:
CLEAR 23999
LOAD ""CODE
—
загрузите файл, далее выполните
SAVE "1"СОDЕ 24000,1000
SAVE "2"CODE 25000,40536
Итак,
на кассете Вы получили два файла. Вновь сбросьте машину и загрузите первый
(более короткий) файл в область экрана оператором
LOAD "1"СОDЕ 16384
—
затем запишите его на диск:
RANDOMIZE USR 15619: REM : SAVE "1"СОDЕ 16384,1000
Второй
файл перенесите на диск любым доступным способом.
Можно несколько ускорить операцию разбиения файла, если после записи
на кассету первого куска (длиной 1000 байт) выполнить оператор CLEAR 24999
(для данного примера, разумеется). Таким образом, мы освобождаем место для
работы TR-DOS, поэтому второй файл можно будет записать на диск непосредственно
из памяти, избежав промежуточных стадий. Обращаю Ваше внимание на то, что после
выполнения оператора CLEAR 24999 область памяти с этого адреса и ниже
отводится под Бейсик, и тем самым портится кусок программы, но поскольку мы
только что этот кусок сохранили на кассете, бояться абсолютно нечего.
Итак,
мы имеем на диске два файла, и если просмотрим каталог оператором LIST
системы TR-DOS, то увидим, что адрес загрузки первого файла 16384 и длина
1000, второго — 25000 и 40536, соответственно (чего, в общем-то, и следовало
ожидать). С этими файлами необходимо поступать следующим образом: первым, без
всяких хитростей (RAMTOP должен быть установлен ниже адреса загрузки файла),
загружается файл "2", а лишь потом — "1". Поскольку
загружаться файл "1" будет в экранную область, перед его
загрузкой, из эсте-
* Как
автор этой программы рекомендую пользоваться версиями с номерами не менее 3.2.
В настоящий момент последняя версия имеет номер 4.3. Программой же DISK DOCTOR
фирмы Technology Researsh, которая поставлялась в комплекте с системой TR-DOS,
пользоваться можно только после принятия некоторой дозы алкоголя.
тических соображений,
рекомендуется сделать цвет INK и PAPER одинаковыми и очистить
экран. Если в программе есть заставка, то она должна загружаться первой, затем
длинный файл, и после очистки экрана — короткий.
Чтобы
загруженный в экран файл поместить на его родное место и запустить программу,
можно воспользоваться подпрограммой в машинных кодах, приведенной на стр. 25. В
разбираемом примере эта подпрограмма будет выглядеть следующим образом:
LD HL,24000
PUSH HL
LD SP,23999
LD HL,16384
LD DE,24000
LD ВС,1000
JP 13251
Опять-таки
имейте в виду, что адаптированная программа будет работать только в том случае,
если она не возвращается в Бейсик.
Во
всех приведенных в данной главе примерах рассматривались программы с одним
кодовым файлом. Все предлагаемые решения можно применить и к программам с
несколькими файлами. Иногда могут возникнуть сложности, однако я уверен:
немного попрактиковавшись, Вы настолько хорошо освоите подобные приемы, что уже
мне у Вас придется учиться, что и как адаптировать на диск.