2. ВНУТРЕННЯЯ СТРУКТУРА ZX SPECTRUM
Компьютер - это машина, которая способна запомнить последовательность команд и затем выполнить их. Конечно, чтобы сделать так, требуется память, в которой команды могут быть сохранены. ZX SPECTRUM имеет два типа памяти. Первый тип - ПЗУ (ROM), в котором содержится фиксированная последовательность инструкций, введенных в машину ее изготовителем.
Второй тип - ОЗУ (RAM). RAM - это "блокнот для записей" компьютера. Когда компьютер выполняет задачу, он непрерывно просматривает, что находится в RAM ("чтение" из памяти) и обновляет содержимое RAM ("запись" в память). SPECTRUM не использует свой "блокнот" для записей случайно. Различные части RAM используются для хранения различных видов информации. Программа BASICa, введенная пользователем, например, хранится в одной части RAM, в то время как переменные, используемые этой программой, хранятся в другом месте. Размер "блокнота" для записей ограничен, и потому машина точна при распределении пространства для информации, которую она хранит. Свободное пространство собрано в одном месте, и, если пользователь хочет добавить строку в свою программу, информация в RAM должна быть "перетасована" по всей длине, используя некоторую свободную область для вставки дополнительной строки.
В значительной степени эта глава посвящена объяснению организации RAM SPECTRUMa, так как многие программы раздела B предназначены для манипуляций с RAM. Глава содержит в себе описание дисплейного файла, атрибутов, буфера принтера, системных переменных, программной области и области программных переменных. В конце раздела описываются стандартные подпрограммы из ROM, к которым ссылаются программы в Разделе В.
Карта памяти
RAM имеет 49152 ячейки памяти. Каждая ячейка может хранить одиночное целое число от 0 до 255 включительно и задается адресом, который является положительным целым числом от 0 до 65535. Адреса от 0 до 16383 зафиксированы для постоянной памяти -ROM. Первый адрес RAM (ОЗУ) - 16384. Табл. 2. 1. - упрощенная карта памяти SPECTRUMa, которая показывает, как используется RAM с адреса 16384.
Дисплейный файл, который хранит отображаемую на экране информацию, занимает ячейки от 16384 до 22527. Атрибуты, которые определяют цвет, яркость и т.д. для каждого знакоместа экрана следуют непосредственно дальше: в ячейках 22528 - 23295.
Первые 5 адресов в колонке Таблицы 2.1. являются фиксированными, т.к. дисплейный файл, атрибуты и т.д. занимают фиксированное положение. Пятая область назначена для карты памяти микродрайва. Это небольшое периферийное устройство представляет собой нечто среднее между магнитофоном и дисководом. Грубо говоря - это дешевая альтернатива дисководу. Скорость его работы достигаете за счет того, что, с одной стороны, лента движется с очень высокой скоростью, а с другой - за счет организации прямого доступ к файлам, как на диске, а не последовательного, как на магнитофонной кассете. Вот для того чтобы иметь в некоем месте хранилище с данными о том, что записано на каждом секторе микродрайва в памяти компьютера и выделен область карты памяти микродрайва. Если микродрайв (а точнее INTERFACE-1, через который он подключается), подсоединен к SPECTRUMy, эта область содержит информацию о его секторах. Если же не подсоединен, эта область не нужна и в этом случае шестая область (информация о каналах) размещена непосредственно за четвертой областью, системными переменными, т.е. стартовый адрес области информации о каналах и всех последующих областей не фиксирован, а может "плавать" вверх-вниз в RAM. SPECTRUM хранит стартовый адрес всех этих областей в системных переменных. Область системных переменных находится перед картой микродрайва в ячейках 23552-23733 включительно. Эти адреса являются все время строго фиксированными.
Стартовый адрес или имя |
Ячейка системной |
Содержимое памяти |
системной переменной |
переменной |
|
16384 |
- |
Дисплейный файл |
22528 |
- |
Атрибуты |
23296 |
- |
Буфер принтера |
23552 |
- |
Системные переменные |
23734 |
- |
Карта микродрайва |
CHANS |
23631 |
Область информации о каналах |
PROG |
23635 |
Адрес начала программы на БЕЙСИКе |
VARS |
23627 |
Адрес начала области программных переменных. |
E-LINE |
23641 |
Адрес области редактирования |
WORKSP |
23649 |
Буфер INPUT |
STKBOT |
23651 |
Стек калькулятора |
STKEND |
23653 |
Свободная область |
SP |
- |
Машинный стек и стек GO SUB |
RAMTOP |
23730 |
Пользовательские подпрограммы в машинном коде. |
UDG |
23675 |
Графика пользователя. |
P-AMT |
23732 |
Физическая вершина ОЗУ. |
Таблица 2.1. Карта памяти. Указатель стека SP хранится не в RAM, а в SP -регистре |
микропроцессора Z80A. |
|
|
Адреса ячеек, которые хранят стартовые адреса всех "плавающих" областей, даны в колонке 2 таблицы 2.1. Адрес области начала программы BASICa, например, хранится в ячейках 23635 и 23636 в области системных переменных.
Примечание: Ссылка к системной переменной с помощью адреса, по которому она хранится, довольно неудобна. По этой причине в Таблице 2.1. в 1-ой колонке даны условные имена системных переменных. Эти имена удобны только для пользователей, в то время как SPECTRUMOM они, естественно, не распознаются. Например, введенная строка: PRINT PROG
даст сообщение об ошибке
"2: variable not found" ("Переменная не найдена").
PEEK и POKE
Карта памяти - это ключ для понимания того, как компьютером используется RAM-память. Для непосредственного управления RAM используются ключевые слова BASICa -РЕЕК и POKE, которые позволяют просмотреть и изменить содержимое любой ячейки памяти. РЕЕК - функция вида:
РЕЕК <адрес>
Адрес - это целое положительное число от 0 до 65535 или арифметическое выражение, которое, выполняясь, дает положительное число. Важно заключить арифметическое выражение в скобки, т.к. РЕЕК 16384 + 2 интерпретируется, как (2 + результат РЕЕК 16384), тогда как РЕЕК (16384 + 2) интерпретируется, как РЕЕК 16386
Значение, выдаваемое функцией РЕЕК - это число, хранящееся по данному адресу в текущий момент. Оно всегда будет положительным от 0 до 255.
Выше объяснялось, что системная переменная PROG хранится по адресу 23635, но значение PROG (т.е. адрес в RAM) всегда больше числа 255. Следовательно, для его хранения необходимы две смежных ячейки с адресами 23635 и 23636. Значение PROG может быть получено с помощью командной строки: PRINT "PROG="; PEEK 23635 + 256 * РЕЕК 23636
Все адреса хранятся в 2-х смежных ячейках в такой форме и могут быть получены вводом: PRINT РЕЕК 1-я ячейка + 256 * РЕЕК 2-я ячейка
Например, если SPECTRUM используется без подсоединенного микродрайва, область карты микродрайва не будет существовать, и информация о каналах будет располагаться непосредственно после области системных переменных, т.о. системная переменная CHANS должна быть такой же, как стартовый адрес карты микродрайва, когда он существует, т.е. 23734. CHANS хранится в 23631 и 23632 и, следовательно, после ввода: PRINT РЕЕК 23631 + 256 * РЕЕК 23632 будет получено значение 23734.
Функция РЕЕК может быть использована также для просмотра содержимого любой из ячеек ПЗУ. Это очень полезно. Просмотр любой ячейки не приводит к разрушению или искажению программы или переменных. Иногда результаты РЕЕК могут быть обманчивыми, т.к. содержимое ячейки, которая просматривалась, может изменяться в течение или непосредственно после выполнения команды просмотра.
Например, если просматривается содержимое ячеек, которые связаны с левым верхним углом экрана дисплея, то результаты, распечатанные в верхнем левом углу экрана, будут уже устаревшими, т.к. в момент вывода изображения мы уже изменили эти ячейки.
Команда POKE более рискованная, чем функция РЕЕК, т.к. задавая ее, пользователь вмешивается в функционирование компьютера. Использование этой команды может быть причиной сбоя машины или ее останова.
Формат команды:
POKE <адрес>,<число>
Адрес - это положительное целое число от 0 до 65535 включительно или арифметическое выражение, которое дает такое число. В этом случае нет необходимости заключать арифметическое выражение в скобки, т.к. РОКЕ - это команда, а не функция (хотя есть негласная заповедь, что лишними скобками программу не испортишь). Число, помещаемое в ячейку, может быть от 0 до 255 включительно.
Дисплейный файл
Обычно дисплей содержит 24 строки по 32 символа. Дисплейный файл занимает ячейки от 16384 до 22527, т.е. 6144 ячейки в общей сложности. Следовательно, количество ячеек, используемое для символа:
6144/(24*32)=8.
Эти 8 ячеек формируют изображение символа экране, называемое знакоместом.
Наиболее легкий путь получения общего впечатления о том, как организован дисплейный файл - это печать (PRINT) картинки на экране, сброс (SAVE) экрана на ленту, очистка экрана (CLS) и загрузка (LOAD) картинки экрана вновь. Программа P2.1 сохраняет (SAVE) и загружает (LOAD) экран, используя графический символ на клавише 5 для создания оригинальной картинки.
Программа P2.1.
100 FOR I=0 ТО 703
110 PRINT " "; : REM символ, находящийся на клавише "5" в G-режиме 120 NEXT I
130 SAVE "Picture" SCREEN$ 140 CLS
150 INPUT "Перемотайте ленту и включите воспроизведение"; z$ 160 LOAD "Picture" SCREEN$
Когда картинка загружается с ленты, видно, что дисплей разделен на три зоны по 8 символьных строк в каждой, а каждая строка разделяется на восемь пиксельных линий. SPECTRUM загружает сначала верхние пиксельные линии для первых восьми строк, затем следующие пиксельные линии тех же восьми строк и т.д. Таким же образом формируются средняя и нижняя части дисплея.
Другой путь понимания формирования дисплея - это рассмотреть, где хранятся 8 байтов, которые используются для формирования символа в верхнем левом углу экрана. Первый байт формирует самую верхнюю 1/8 часть символа и размещается в начале дисплейного файла по адресу 16384.
Команда РОКЕ 16364,0 очистит верхнюю линию пикселей самого верхнего левого знакоместа, в то время, как РОКЕ 16384,255 закрасит всю эту линию. При помещении в эту ячейку числа от 0 до 255 мы получим в этом месте экрана различные штрихи. Вторая сверху линия в первом знакоместе на экране не сформирована числом, хранящимся в ячейке 16385, - эта ячейка используется для верхней линии пикселей в соседнем символе. Вторая линия сверху в первом знакоместе формируется числом, хранящимся в ячейке 16384+32*8=16640.
Подобным же образом вычисляются адреса оставшихся шести линий этого знакоместа.
Следовательно, образ символа в верхнем левом углу экрана определяется содержимым адресов 16384, 16640, 16896, 17152, 17408, 17664, 17920, 18176.
Программа P2.2. позволяет Вам экспериментировать, помещая различные числа в эти восемь ячеек.
Программа P2.2. Программа для создания символа в верхнем левом углу экрана.
10 REM подпрограмма установки символа в верхнем углу экрана
20 INPUT "Символ состоит из восьми байтов, каждый из которых - число в диапазоне от 0 до
255. Введите номер байта (от 0 до 7)";n 30 IF n<0 OR n>7 OR n<>INT n THEN BEEP 0.2,24: GO TO 20 40 INPUT "Ввести содержимое байта"^
50 IF m<0 OR m>255 OR m<>INT m THEN BEEP 0.2,24: GO TO 40 60 POKE 16384+8*32*n,m
Программа P2.3. Программа декодирования атрибута.
10 REM декодер атрибутов
20 DATA "Black", "Blue", "Red", "Magenta", "Green", "Cyan", "Yellow", "White", "Bright",
"Flash" 30 DIM C$(8,7) 40 FOR I=1 TO 8 50 READ C$(I) 60 NEXT I
100 REM Декодер атрибутов
110 INPUT "Ввести число от 0 до 255. Эта программа декодирования интерпретирует его в файл атрибутов"^
120 IF n<0 OR n>255 OR n<>INT n THEN BEEP .2,24: GO TO 110
200 PRINT "Цвет символа - "; c$(1+n-8*INT(n/8))
210 PRINT "Цвет фона - "; C$(1+INT(n/8)-8*INT(n/64))
220 IF INT(n/64)=1 OR INT(n/64)=3 THEN PRINT "СИМВОЛ - BRIGHT"
230 IF n>127 THEN PRINT "Символ будет мерцать (FLASH)"
300 PRINT AT 6,0; "::::::::::::::::::::::::::::::::"
310 FOR i=22720 TO 22751
320 POKE i,n
330 NEXT i
500 INPUT "Для повторения - ENTER";z$
510 CLS
520 GO TO 110
Каждая ячейка в дисплейном файле определяет восемь пикселей на экране. При этом число, которое хранится в данной ячейке, преобразуется в двоичную форму и затем устанавливаются восемь пикселей, соответственно двоичным цифрам. Например, 240 после преобразования в двоичное число дает:
11110000
Следовательно, если ячейка содержит число 240, четыре из восьми пикселей, соответствующие единицам, будут высвечены, а оставшиеся нет. Следовательно, дисплейный файл состоит из 6144 ячеек памяти по 8 ячеек для одного знакоместа.
Каждая ячейка определяет горизонтальную полосу из восьми пикселей. Ячейки, относящиеся к данному знакоместу, не расположены последовательно одна за другой.
Атрибуты
Содержимое дисплейного файла определяет, какие пиксели высвечиваются на экране, цвет фона (PAPER), символа (INK), яркость (BRIGHT) и мерцание (FLASH) определяются с помощью атрибутов. Область атрибутов занимает ячейки 22528 - 23295 - по одной ячейке для каждого из 768 знакомест.
Соответствие между содержимым ячеек памяти файла атрибутов и самими атрибутами - следующее:
Значение атрибута = 128*FLASH + 64*BRIGHT + 8*PAPER + INK
FLASH и BRIGHT принимают значение 1, если соответствующее условие установлено, а PAPER и INK принимают значение требуемого цвета, как показано на клавиатуре (красный, например 2).
Программа P2.3. декодирует атрибуты, т.е. данное значение атрибута распечатывает с соответствующим цветом PAPER и INK.
Буфер принтера
256 ячеек ОЗУ, следующие за областью атрибутов, используются, как буфер для хранения строки символов, которая должна быть передана на принтер.
Многие программы в Разделе B будут использовать буфер принтера для передачи данных BASICа или от клавиатуры в подпрограммы. Буфер подходит для этой цели, т.к. его ячейки фиксированы и маловероятно, что пользователь пожелает его использовать для других целей.
Единственно важное ограничение в этом случае - не использовать команды BASICa, которые требуют работы с принтером - LLIST, LPRINT, COPY.
Есть еще и ограничение для владельцев 128-килобайтных машин. У них нет буфера принтера. Дело в том, что буфер принтера предназначался в оригинальной модели для поддержки недорогого специализированного узкопечатного ZX-принтера. В фирменной модели 128-килобайтных машин есть порт подключения полноценного матричного принтера, обладающего собственным буфером и необходимость в этом буфере отпала, зато в этих моделях необходимо больше системных переменных и под них отдали область буфера ZX-принтера. Теперь, если в режиме 128К пользователь что-либо зашлет в эту область, то нарушив системные переменные он выведет программу из строя.
Область программ на BASICe
Обычно эта область начинается с адреса 23755 и на нее указывает содержимое системной переменной PROG (23635,23636), но есть и исключения за счет некоторых видов периферийных устройств.
Если, например, к компьютеру подсоединен микродрайв, то начало этой области сдвигается, в этом самом общем случае начало области программ на BASICe и определяют с помощью системной переменной PROG. Ниже предполагается, что такая периферия не подсоединена.
Программа P2.4. распечатывает содержимое 18-ти ячеек в начале программной области, как показано на рис. 2.1. В этих 18 ячейках хранится первая строка данной программы.
10 REM Реек program
20 FOR i=23755 ТО 23772 30 PRINT i,PEEK i 40 NEXT i
Программа P2.4. Программа для просмотра содержимого первых 18-ти ячеек в программной области.
23755 |
0 |
23756 |
10 |
23757 |
14 |
23758 |
0 |
23759 |
234 |
23760 |
80 |
23761 |
101 |
23762 |
101 |
23763 |
107 |
23764 |
32 |
23765 |
112 |
23766 |
114 |
23767 |
111 |
23768 |
103 |
23769 |
114 |
23770 |
97 |
23771 |
109 |
23772 |
13 |
Рис.2.1. Форма, в которой строка 10 REM реек program хранится в программной
области.
Номер строки (10) хранится в первых двух ячейках в форме: Номер строки = 256*РЕЕК первый адрес + РЕЕК 2-й адрес.
Следующие 2 ячейки: 23757 и 23758 хранят длину оставшейся части строки, начинающейся в ячейке 23759. В нашем случае: 14+256*0=14 Т.о. следующая строка начинается с ячейки: 23759+14=23773
Ячейка 23759 хранит в себе число 234, которое является кодом ключевого слова (токена) REM. Следующие 12 ячеек хранят коды символов одиннадцати букв и пробела, составляющих фразу Peek program. Последняя ячейка хранит число 13, которое является кодом для ENTER, определяющим конец строки
Таблица 2.2. показывает метод кодирования программы в программной области.
Ячейки |
Номер строки |
1 и 2 |
Номер строки |
3 и 4 |
Длина строки, исключая первые 4 ячейки |
5 |
Код команды |
Конец |
Символ ENTER, число 13 |
Табл. 2.2. Этот метод используется для кодирования строк программы. |
Момент, который опущен в таблице - это описание метода хранения числовых
значений, имеющих место в программе. Этот метод может быть исследован на примере строки:
10 LET а=1443
Введите ее в программу P2.4. На рис.2.2 показан результат работы программы в этом случае.
23755 |
0 |
23756 |
10 |
23757 |
14 |
23758 |
0 |
23759 |
241 |
23760 |
97 |
23761 |
61 |
23762 |
49 |
23763 |
52 |
23764 |
52 |
23765 |
51 |
23766 |
54 |
23767 |
0 |
23768 |
0 |
23769 |
163 |
23770 |
5 |
23771 |
0 |
23772 |
13 |
Рис. 2.2. Формат, в котором строка 10 LET a=1443 хранится в программной области.
Ячейки 23755-23758 такие же, как в прошлом примере. Затем следуют коды для LET, a, =, и четыре кода цифр, которые вместе формируют число 1443. Следующий элемент, находящийся в ячейке 23766, - это код 14. Этот код указывает, что следующие 5 ячеек хранят число в специальном пятибайтном формате. Линия заканчивается в ячейке 23772 вводом символа ENTER, как и ранее.
* * *
Примечание ИНФОРКОМа. Получается так, что в одной строке число как бы записано дважды. Первый раз своими символами, а второй раз - в пятибайтной форме после кода 14. Зачем это нужно?
Дело в том, что первое представление используется для того, чтобы БЕЙСИК-интерпретатор знал, что вам показать на экране, а второе - используется для расчетов во внутреннем калькуляторе компьютера. (О калькуляторе читайте в т. 1 и 2 нашего трехтомника).
Самое интересное, что они могут и не совпадать. В этом случае Вы на экране будете видеть одно, а программа будет обрабатывать совсем другое число, и этим нередко пользуются в защите программ. Например, Вы видите на экране LET а=1257: GO TO а и пытаетесь проследить работу программы, а на самом деле там было записано нечто совсем другое и компьютер делает переход не к строке 1257, а туда, куда надо.
Желающие могут посмотреть загрузчик программы BOMBJACK. В череде относительно несложных вывертов этот там стоит одним из первых. Но если на него
"клюнуть", атака на программу никак не получится.
* * *
Цифровой пятибайтный формат
Пять ячеек памяти используются для хранения чисел в программе на BASICe (исключая номера строк). Целые числа в диапазоне от -65535 до +65535 хранятся таким же образом, как в формате Z80A. Для этих чисел первые две ячейки и последняя содержат 0, а третья и четвертая хранят число в двухбайтной форме:
Число = РЕЕК 3-я ячейка + 256* РЕЕК четвертая ячейка
Таким образом 16533 хранится в пяти ячейках как
0 0 169 64 0
потому, что
169+256*64=16553
Дробные числа хранятся в формате с плавающей запятой таким образом: экспонента в первой ячейке, а мантисса в следующих четырех ячейках, т.е.:
число = мантисса * 2Лэкспонента
Первая ячейка мантиссы используется также для определения знака числа. Если ячейка содержит значение в пределах от 0 до 127, число положительное, если нет -отрицательное.
Программа P2.5 может быть использована для восстановления дробного числа из составляющих его пяти компонентов.
10 PRINT "Ввести экспоненту и четыре байта мантиссы. Все числа должны находиться между 0 и 255 включительно."
20 INPUT e,a,b,c,d
30 PRINT ,, " Exponent= ";e
40 PRINT "Mantissa= "; a,,b,,c,,d
50 PRINT ,,"The number= "; (2*(a<128)-1)*2~(e-160)* (((256*(a+128*(a<128))+b)*256+c)*256+d)
Программа P2.5. Эта программа восстанавливает дробное число.
Область переменных
Область переменных начинается в ячейке, адрес которой хранится в системной переменной VARS (ячейка 23627). Как бы ни была объявлена новая переменная, т.е. в программе или непосредственным вводом с клавиатуры, для нее резервируется соответствующее количество свободного пространства в этой области.
Все имена переменных начинаются с буквы. Различий между верхним и нижним регистром нет. Эти ограничения позволяют SPECTRUMy манипулировать с кодом первого символа каждой переменной и, таким образом, он может различить шесть типов переменных просмотром диапазона, в котором находится код.
Все цифровые переменные с односимвольными именами, например, имеют коды в пределах от 97 до 122; буква a - 97; b - 98; c - 99 и т.д. Подобным же образом цифровые массивы имеют коды в пределах 129 - 153, т.е. a - 129; b - 130; c - 131 и т.д. Диапазоны кодов представлены в таблице 2.3.
Длина каждого типа переменной также показана в таблице 2.3.
Тип переменной |
Диапазон символьного кода |
Длина в области переменных |
Цифровой |
97 - 122 |
6 |
(односимвольное имя) |
|
|
Цифровой |
161 - 186 |
5 + длина имени |
(многосимвольное имя) |
|
|
Цифровой массив |
129 - 154 |
4 + 2 * размерность + 5 * общее |
|
|
количество элементов. |
Управляющая |
225 - 250 |
18 |
переменная цикла FOR- |
|
|
NEXT |
|
|
Символьная строка |
65 - 90 |
3 + длина строки |
Символьный массив |
193 - 218 |
4 + 2 * размерность + общее число |
|
|
элементов. |
Таблица 2.3. Переменные. Диапазон кодов и длина переменных. |
Подпрограммы ПЗУ
Некоторые из представленных в книге программ (раздел В) используют стандартные подпрограммы ПЗУ:
RST 16 - распечатывает содержимое аккумулятора.
CALL 3976 - вставляет символ, хранящийся в аккумуляторе, по адресу, хранящемуся в паре регистров HL.
CALL 6326 - если аккумулятор хранит код 14, устанавливается нулевой флаг и
увеличивается пара регистров HL в пять раз.
CALL 6510 - возврат в HL адреса в ОЗУ той строки, номер которой был передан в эту подпрограмму через HL.