┌──────────────────────────────────┐ │ Бейсик-48К │ └──────────────────────────────────┘ ────────────────────────────────────────── (с) Alone Coder/Any ────────────────────────────────────────── Сегодня я собираюсь рассказать об одном очень эффективном способе повысить произ- водительность интерпретатора бейсика (48 Basic), встроенного в ZX-Spectrum, при об- работке больших массивов данных. Известно, что классическим способом пе- ремещения блоков данных в памяти при прог- раммировании в машинных кодах (ассемблере) является команда LDIR, а также её родная сестра - команда LDDR. На бейсике же ниче- го подобного не предусмотрено, и поэтому, скажем, "ZX-Ревю" советует использовать для таких случаев подгружаемые или созда- ваемые через READ-DATA-POKE машинно-кодо- вые процедуры. Но я - за чистоту родного бейсика! ;) Можно закрутить цикл,перебирающий адре- са и перемещающий по одному байту за про- ход,но такой вариант будет выполняться как минимум в сотни раз медленнее,чем машинный код - это очень медленно. Но мы вспомним, что в языковом аппарате "бейсика" заложена функция, которая выпол- няется со скоростью LDIR.Функция эта - ко- пирование строковых переменных и их участ- ков! К сожалению,в бейсике нельзя задать пе- ременную,проходящую через экранную область (а нам именно это и нужно, так как копиро- вание больших блоков чаще всего требуется для обработки экрана: его сдвига, сохране- ния в памяти, восстановления и т.п.) Поэтому попробуем создать фиктивную пе- ременную, пересекающую экран,своими средс- твами. Как известно, двухбайтный адрес начала переменных бейсика хранится в системной переменной VARS (23627-23628). Переменные в этой области следуют одна за другой,ука- зывая друг на друга по цепочке. Несколько форматов переменных отличаются тремя стар- шими битами в первом символе имени пере- менной. Строковые переменные имеют формат: %010aaaaa <мл.байт длины> <ст.байт длины> <символы ("длина" штук)> Где aaaaa - младшие пять бит символа имени переменной (у строковых переменных односимвольные имена), а "длина" - длина содержательной части строки, т. е. сколько в этой строке символов. Получается,что достаточно заполнить три первых байта формата переменной,и мы можем заполучить строку произвольной длины с во- зможностью копирования внутри неё, т. е. с возможностью быстрого перемещения блоков. Но задача осложняется тем,что последняя обрабатываемая строковая переменная всегда пересылается бейсик-интерпретатором в на- чало области переменных (по крайней мере, мне так показалось), да ещё и адрес этой области нефиксирован - зависит от длины программы и конфигурации компьютера, да и вдобавок,создав такую переменную,мы теряем все другие переменные бейсика, ибо на них уже больше ни одна предыдущая переменная не указывает. (Ведь предыдущих переменных у нас всего одна штука - больше мы создать не можем, потому что см. начало абзаца :)) Значит, единственный правильный выход - переместить область переменных по фиксиро- ванному адресу в памяти, создать идентифи- катор фиктивной строковой переменной, про- извести с помощью неё нужные операции ко- пирования, а после этого восстановить ис- ходный адрес области переменных. ┌────────────────────────────────────────┐ │ BASIC program Length: #01A8=424 │ └────────────────────────────────────────┘ 1 LIST : POKE VAL "23627", CODE " CLEAR ": POKE 23628, NOT PI 1000 LET b$(39968 TO 40223)=b$(16129 TO ): LET b$(16129 TO 17920)=b$(16385 TO ): LET b$(17921 TO 18144)=b$(4e4 TO ) 1010 LET b$(18145 TO 18176)=b$(18177 TO ) 1020 LET b$(4e4 TO 40223)=b$(18209 TO ): LET b$(18177 TO 19968)=b$(18433 TO ): LET b$(19969 TO 20192)=b$(4e4 TO ) 1030 LET b$(20193 TO 20224)=b$(39968 TO ): GO TO 9 Эта программа (см. также приложение к газете) задаёт переменную b$, начинающуюся с адреса 253 (CODE " CLEAR "=253).По этому адресу во ВСЕХ версиях бейсика находится участок таблицы токенов, который и опреде- ляет переменную с этим именем и длиной около 50 килобайт. Поскольку идентификатор переменной на- чинается с адреса 253, то первый символ ( b$(1) ) этой переменной хранится по ад- ресу 256,второй - по адресу 257 и т.д. Так что все указанные в программе числа - это экранные адреса минус 255. Программа скроллирует две экранных тре- ти. Это упрощённый вариант программы,пред- назначенный только для иллюстрации метода. Поэтому выход из неё не предусмотрен. Если вы во время её выполнения нажмёте BREAK,то даже не сможете выполнить RUN,т.к. область переменных была перемещена и не вернулась обратно. Практический способ сохранить и пра- вильно восстановить системную переменную VARS в условиях отсутствия доступа к пере- менным состоит в копировании содержимого ячеек 23627 и 23628 по некоему известному адресу в памяти и восстановлении этого со- держимого сразу после выполнения "нечест- ного" участка программы. Конечно,наша созданная переменная может и указывать на последующие, но для этого она должна кончаться там, где они начинаю- тся.Такая переменная получится очень коро- ткой, создай мы её в первой половине памя- ти, но если она будет начинаться выше 25000,то она сможет захватить в себя и эк- ран, и верхние области памяти, и при этом ещё может указывать на другие переменные. Разумеется, в этом случае программа не до- лжна использовать другие строковые пере- менные,или,по меньшей мере,должна переклю- чать VARS перед их использованием. Кстати, если бы переменная была создана по адресу 65534, то нумерация её символов совпадала бы с адресами,по которым эти си- мволы хранятся. У меня большое подозрение, что так работает функция "MEMORY$()" в Бе- та-Бейсике, но она написана с помощью ма- шинного кода, а у нас - чистый бейсик! Spectrum Basic rulez! & it's not portable :)