Глава 6. С И С Т Е М Н Ы Е П Е Р Е М Е Н Н Ы Е Системные переменные хранятся с адреса #5C00 (23552) до области, занимаемой прог- раммой Бейсик. Программы из памяти ROM ис- пользуют ее для запоминания информации, описывающей состояние компьютера. Ниже бу- дут рассмотрены те переменные, которые мо- гут модифицироваться и использоваться программистом. Остальные лучше не трогать, так как это может привести к порче опера- ционной системы. Описываемые переменные разделим (согласно специфических функций, а не положения в памяти) на 5 групп: - хранящие важные для системы адреса; - обслуживающие клавиатуру; - описывающие состояние системы; - связанные с каналами и потоками; - обслуживающие экран телевизора. 6. 1 Важные для системы адреса ERR_SP #5C3D (23613) STKEND #5C65 (23653) VARS #5C4B (23627) RAMTOP #5CB2 (23730) PROG #5C53 (23635) P_RAMT #5CB4 (23732) E_LINE #5C59 (23641) CHANS #5C36 (23606) WORKSP #5C61 (23649) UDG #5C7B (23675) STKBOT #5C63 (23651) Применение этих переменных описано в предыдущей главе. Естественным использова- нием этих переменных может быть перерасп- ределение размеров свободной памяти, либо занятой программой, переменными и т. д. Только переменная RAMTOP может быть легко модифицирована из Бейсика посредством CLEAR K. К сожалению, эта команда имеет также и другие побочные действия, что вре- менами делает ее использование невозмож- ным. P_RAMT Содержит адрес последней, физически присутствующей в компьютере, ячейки памя- ти. Следовательно, может быть использована для распознавания программой в какой моде- ли компьютера ZX-SPECTRUM она загружена (16K или 48K). CHARS Благодаря этой переменной можно опреде- лить собственные формы вывода. После раз- мещения их в память RAM под адресом K дос- таточно задать переменной CHARS значение K-256. Начиная с этого момента, все текс- ты, включая программный листинг, будут пе- чататься нашими новыми знаками. Этим спо- собом можно изменить очертания всех симво- лов с кодами от 32 до 127. Следует под- черкнуть, что так модифицируется только очертания знаков, но не их значения, кото- рые зависят от кодов символов. Можно ис- пользовать эту переменную для трюков, де- лающих текст программы абсолютно нечитае- мым. Достаточно уменьшить значение CHARS на 8, и тогда в распечатке программы труд- но будет найти какой-либо смысл. Зато над- писи, выводимые запущенной на выполнение программой, останутся разборчивыми, если будут заблаговременно сдвинуты на одно значение кода, т. е. в исходном тексте по- местим "B" вместо "A", "O" вместо "N" и т. д.. UDG Польза от размещения этого адреса в списке для переменных состоит в том, что этот блок мы можем перемещать в памяти. Столь же ценной является возможность ис- пользования нескольких наборов нетиповых символов одновременно. В этом случае, пе- ред выводом данного знака требуется моди- фицировать UDG, присваивая переменной зна- чение набора, необходимого в данный мо- мент. Модификация остальных переменных этой группы очень опасна и может легко привести к сбою и зависанию операционной системы. ERR_SP Эта переменная указывает основание ма- шинного стека. Там, в свою очередь, поме- щен адрес процедуры в памяти ROM, отвечаю- щей за обслуживание всех ошибочных ситуа- ций, требующих прерывание программы и вы- дачи соответствующего сообщения. Под ошиб- кой здесь понимается также и нормальное завершение программы, сигнализируемое сообщением 0 OK. Страстные программисты, знающие ассемблер Z80 могут, благодаря этому, писать собственные программы обра- ботки ошибок, что позволяет, между прочим, добавление новых команд к языку. Модифика- ция ERR_SP с уровня Бейсика всегда ведет к краху системы в момент возникновения си- туаций, требующих вывода любого сообщения. Это часто используется для защиты програм- мы от несанкционированного просмотра и ко- пирования. Этот метод в соединении с за- писью программ с помощью SAVE F LINE..., а также с исключением возможности считывания программы инструкцией MERGE обычно пол- ностью позволяет обезопасить программу от менее грамотных пиратов. К сожалению, спа- сения от многочисленных копирующих прог- рамм нет. 6. 2 Переменные, обслуживающие клавиа- туру KSTATE #5C00 (23552) Эта переменная построена из 8 байт и используется для чтения клавиатуры и обс- луживания самоповторяемости клавиш. Для программиста лишь ячейка с адресом #5C04 (23556) может иметь значение. Она содержит значение 255, если ни одна клавиша не на- жата, или код основного значения нажатой клавиши в режиме C (большая литера алфави- та или цифра). PEEK 23556 дает поэтому тот же самый эффект, что и CODE INKEY$ в режиме C. Достоинством является факт, что значение не зависит от состояния курсора (L или C). В случае нажатия нескольких клавиш одновременно всегда будет распозна- на первая (INKEY$ в такой ситуации может игнорировать все). Клавиши <CS> и <SS>, нажимаемые по отдельности, не воздействуют на нашу ячейку, но нажатые вместе дают код 14. Кроме того, комбинации <CS/9>, <CS/3>, <CS/4>, <CS/2> выдают соответственно коды 15, 4, 5, 6 (эти коды ловит также CODE INKEY$). LAST_K #5C08 (23560) Эта байтовая переменная хранит код пос- ледней нажатой клавиши, независимо от то- го, нажимают на нее или нет. В случае на- жатия нескольких - будет запомнен код пер- вой. В отличие от предыдущей переменной, LAST_K следит за состоянием курсора. С этой переменной частично связана следующая переменная. FLAGS #5C3B (23611) Сколько раз переменная LAST_K принимает новое значение, столько раз пятый бит пе- ременной FLAGS устанавливается в 1. Это важно, если мы желаем распознать многок- ратное нажатие на одну и ту же клавишу. В свою очередь, третий бит этой переменной, вместе с содержимым MODE, позволяет рас- познать в какой ситуации относительно чте- ния клавиатуры должен быть использован курсор K. Однако, эту информацию можно ис- пользовать лишь с уровня ассемблера. 7 бит переменной FLAGS сигнализирует системе, что пришла выполняемая команда с клавиату- ры или из программы. Размещенная в прог- рамме инструкция POKE 23611, 0 прервет ее выполнение сообщением 0 OK. REPDEL #5C09 (23651) и REPPER #5C0A (23652) Две эти переменные необходимо рассмат- ривать одновременно. Первая из них опреде- ляет как долго надо нажимать клавишу, что- бы заработал автоповтор, а вторая опреде- ляет время между считыванием с клавиатуры. В обеих переменных время дано в 1/50 се- кунды. По началу эти переменные инициали- зированы значениями 35 и 5, что обозна- чает, что нажатая клавиша после 0. 7 сек начинает саморазмножаться с темпом 10 зна- ков в сек. В процессе считывания с клавиа- туры эти значения можно уменьшить до 0. Придавая им значения 0, добиваются наи- большей остановки, продолжающейся столько же, сколько PAUSE 256. Занесение в эти ячейки значения 1 приводят к тому, что ра- бота со SPECTRUM становится трудной, но возможной (ввод любой директивы с клавиа- туры будет требовать от оператора отличной реакции и чувствительности в пальцах). RASP #5C38 (23608) и PIP #5C39 (23609) Эти переменные определяют звук, сопро- вождающий ввод данных. RASP задает дли- тельность (в 1/50 сек) предупредительного ворчания, когда SPECTRUM не желает больше считывать данные. Начальное значение RASP=64 (1. 26 сек). PIP определяет дли- тельность звука, подтверждающего нажатие клавиши. Начальное значение PIP=0. Стоит помнить, что RASP и PIP, в отличие от большинства других системных переменных, не инициализируются заново инструкцией NEW. 6. 3 Переменные состояния системы Эти переменные позволяют системе конт- ролировать ситуацию и верно интерпретиро- вать очередные программные строки. NEWPPC #5C42 (23618) и NSPPC #5C44 (23620) Первая из них (2 байта) содержит номер строки, а вторая (1 байт) осуществляет пе- реход. Следующие команды вызывают непос- редственный переход к M-й инструкции в L-й строке, следовательно, действуют значи- тельно точнее команды GOTO L. POKE 23618, L-256*(INT(L/256)): POKE 23619, INT(L/256): POKE 23620, M PPC #5C45 (23621) и SUBPPC #5C47 (23623) Эти переменные содержат соответственно номер строки и номер выполняемой команды. Вместе с переменной ERR_NR они могут слу- жить для завершения программы с ранее за- данным сообщением без провоцирования фак- тической ошибки. С этой целью программу следует завершить инструкцией GOTO 9999, а в этой строке поместить команды: 9999 POKE 23621, L-256*INT(L/256): POKE 23622, INT(L/256): POKE 23610, M-1 : POKE 23623, K В этом случае программа завершится сообщением: M ТЕКСТ L: K . ERR_NR #5C3A (23610) В этой ячейке появляется номер-1 ошиб- ки, которая произошла и будет сигнализиро- ваться соответствующим сообщением. Содер- жимое этого байта может быть ценным при написании собственных процедур обработки ошибок на ассемблере, т. к. сразу опреде- ляет причину прерывания программы. E_PPC #5C49 (23625) Эта переменная (2 байта) содержит номер текущей строки и доступна для редактирова- ния. Ее модификация вызовет тот же эффект, что и LIST N, но без вывода программы на экран. Это делает возможным выбор с кла- виатуры строки программы для модификации, а затем копирования ее в нижнюю часть эк- рана и корректировку без уничтожения со- держимого экрана. MODE #5C41 (23617) Эта переменная информирует редактор ка- кой курсор должен использоваться в данный момент. Система использует следующие зна- чения: 0-L, C или K, 1-E, 2-G. Эти числа затем используются в различных выражениях для назначения кода символу, который дол- жен высвечиваться как курсор. Программируя на Бейсике можно только склонить SPECTRUM, чтобы в ближайшей инструкции INPUT вместо стандартного курсора L или C использовался курсор G или E. Причем режим E будет действовать только для первого вводимого символа. Режим E включится POKE 23617, 1. Интересные эффекты дает размещение в этой переменной других значений (отличных от 1, 1, 2). POKE 23617, K для K=3,..., 127 вы- зывает курсор G, хотя на экране вообще не будет печататься литера G, а нечто другое. POKE 23617, K для K=0, 128,..., 255 уста- навливается режим L или C, но с выводом на экран другого мерцающего курсора. FLAGS #5C6A (23658) Эта переменная определяет, какой необ- ходим режим L или C. За это отвечает 3-й бит FLAGS2. POKE 23658, 0 устанавливает режим L, а POKE 23658, 8 - режим C. Подоб- ные изменения получают с клавиатуры с по- мощью CS/2. DF_SZ #5C6B (23659) Эта переменная содержит число строк нижней части экрана, зарезервированных для системных сообщений и данных, вводимых с помощью INPUT. Инициализируется значением 2. Практически не используемая, хотя иног- да может быть использована для защиты программ от прерываний. Помещение в нее 0 вызывает зависание системы, как только возникает необходимость вывода чего-нибудь в нижнюю часть экрана (например, сообщения о нажатии BREAK). Однако это не выгодное оружие, т. к. одновременно делает невоз- можным применение инструкций INPUT, CLS, а также не позволяет задать вопрос "SCROLL?". OLDPPC #5C6E (23662) и OCPPC #5C70 (23664) Они содержат номер строки и команды в строке, к которым будет осуществлен пере- ход в случае выдачи команды CONTINUE. Мо- дификация этих переменных в программе поз- воляет найти точнейшую альтернативу инст- рукции GO TO. В некоторых ситуациях это лучше, чем модификация NEWPPC и NSPPC, т. к. переход наступает лишь при встрече с CONTINUE, а не сразу же после модификации переменных. Эти переменные автоматически корректируются системой всякий раз, когда наступает прерывание программы с сообще- нием, отличным от 0 OK. SEED #5C76 (23670) Эта основа генератора псевдослучайных чисел. Использование SEED рассматривалось при описании функции RND. FRAMES #5C78 (23672) Три байта составляют внутренние часы ZX-SPECTRUM. Они представляют число PEEK 23672+256*PEEK 23673+65536*PEEK 23674 и определяют сколько 1/50 сек прошло с мо- мента инициализации системы. Максимальным значением является 2^24-1=16777215, что отвечает 3 суткам 21 часу 12 минутам и 24. 3 секундам. Точность таймера составляет около 0. 01% или менее 9 сек в сутки. Этот таймер включается на то время, когда SPECTRUM обслуживает внешние устройства (принтер, магнитофон, динамик), а также во время выполнения программы в машинном ко- де, которые выключают или обходят контроль за замаскированными прерываниями. DATADD #5C57 (23639) Эта переменная хранит адрес элемента в списке DATA, который будет считан очеред- ной инструкцией READ (это близко к правде, но является хорошим приближением этих двух ячеек). Запоминая их содержимое и исполь- зуя его потом, можно получить точнейшую альтернативу команды RESTORE K. SCR_CT #5C8C (23692) Этот байт определяет, после вывода скольких строк +1, на экране должен поя- виться вопрос "SCROLL?". Если надо, чтобы вывод не прерывался, то , по крайней мере, один раз на 255 выведенных строк необходи- мо в эту ячейку занести значение 255. Если нам надо прервать вывод раньше, то нужно присвоить этой переменной значение меньшее 23. 6. 4 Переменные, обслуживающие экран телевизора Эта группа переменных отвечает за пра- вильные взаимодействия компьютера с теле- визором. Одна из них управляет цветом, другие определяют место вывода очередного знака или графического символа. BORDCR #5C48 (23624) Эта переменная содержит атрибуты, опи- сывающие нижнюю часть экрана, а также цвет рамки. В обычных условиях ZX-SPECTRUM не позволяет устанавливать одинаковый цвет для фона и чернил в нижних строках (поль- зователь всегда должен видеть вводимые им символы). Спецификаторы цветов в списке INPUT будут действенны только для текстов, печатаемых в нижней части экрана, но цвет чернил для вводимых данных всегда устанав- ливается в 9 (белый или черный, в зависи- мости от цвета фона). Обойти это можно (например, если компьютер должен считывать с клавиатуры тайный пароль) используя команду POKE 23624, 128+F+64*B+8*P+I и присваивая литерам F, B, P, I значения па- раметров команд FLASH, BRIGHT, PAPER и INK, необходимых для получения желаемого эффекта. Тем, кто не убежден, рекомендуем получить этот эффект другим способом: BORDER 3 : POKE 23624, 222 : CLS. ATTR_P #5C8D (23693) и ATTR_T #5C8F (23695) Обе переменные однобайтовые и хранят значения атрибутов FLASH, BRIGHT, PAPER и INK. Литера P обозначает величины, уста- новленные постоянно соответствующими ко- мандами для всей программы, литера T - те- кущие значения, устанавливаемые теми же самыми командами, размещенными в списках соответствующих пишущих и рисующих команд. При отсутствии спецификаторов цвета в списках пишущих инструкций, переменная ATTR_P копируется в ATTR_T. Способ хране- ния информации о цветах в одном байте опи- сан в главе "Использование памяти". Пере- менная ATTR_P может быть использована в программе Бейсика для установления всех атрибутов одной инструкцией POKE. ATTR_T, в свою очередь, может быть важна для прог- раммирующих в машинном коде, так как, обычно, используются процедурами памяти ROM для установления заданных цветов. MASK_P #5C8E (23694) и MASK_T #5C90 (23696) Эти однобайтовые переменные используют- ся при реализации команд FLASH, BRIGHT, PAPER, INK с параметром 8. Значение литер P и T в именах переменных такое же самое, как для переменных ATTR. Установление ка- кого-либо бита этих переменных в 1 озна- чает, что бит с тем же самым номером в соответствующем байте атрибутов должен ос- таться неизменным. Обратим внимание, что команда INK 8 устанавливает в 1 все 3 младших бита переменной MASK_P. Модифици- руя эту переменную инструкцией POKE можем, например, установить в 1 только один млад- ший бит. Тогда будет получен эффект фильт- ра. Неизменной в цвете чернил останется только основная синяя компонента, в то время как остальные могут подвергаться из- менениям. (Обратим внимание на то, что нумерация цветов совсем случайна. Цвет си- ний - 1, красный - 2, зеленый - 3 это ос- новные цвета, смесь которых позволяет по- лучить все остальные. В ZX-SPECTRUM роль смешивания выполняет добавление номеров соответствующих цветов. COORDS #5C7D (23677) Два последовательных байта этой пере- менной содержат координаты (X, Y) точки на экране, в которой завершила рисование последняя инструкция PLOT, DRAW, CIRCLE. Модификация этой переменной дает тот же самый эффект, что и PLOT OVER 1, K, N: PLOT OVER 1, K, N, т. е. смещение указате- ля экрана без рисования какой-либо точки или линии. SPOSN #5C88 (23688) Эта переменная (2 байта) содержит зна- чения 33-K, 24-M, где K, M - координаты последнего выведенного на экран знака. Непосредственная модификация этих перемен- ных затруднительна, т. к. необходимо од- новременно модифицировать DF_CC. DF_CC #5C84 (23684) Эта переменная содержит адрес байта на экране, с которого начинается вывод оче- редного символа инструкцией PRINT. Модифи- цируется только вместе с Z_POSN. Значи- тельно проще применить команду PRINT AT K, N. SPONSL #5C8A (23690) и DFCCL #5C86 (23686) Переменные, аналогичные S_POSN и DF_CC, описывающие нижнюю часть экрана. P_FLAG #5C91 (23697) Переменная, содержащая информацию о ре- жиме печати и рисования на экране. Описы- вает режимы, установленные Бейсиком с по- мощью инструкции INVERSE, OVER, INK 9 и PAPER 9. Нечетные биты соответствуют пос- тоянному заданию этих режимов, четные вре- менному. __________________________________ | | временно | постоянно | | | бит | бит | |-----------|----------|-----------| | OVER 1 | 0 | 1 | | INVERSE 1 | 2 | 3 | | INK 9 | 4 | 5 | | PAPER 9 | 6 | 7 | |___________|__________|___________| Если необходимо установить постоянно OVER 1: INVERSE 1: INK 9: PAPER 9, то вместо 4-х команд достаточно одной POKE 23697, 2+8+32+128. ВНИМАНИЕ: названия системных переменных не распознаются Бейсиком. Они введены ав- торами операционной системы и приняты во всей литературе, относящейся к ZX-SPECTRUM.