Срелства "ZX спектрум"
Настало время рассмотреть средства вашего "ZX спектрум", полезные при разработке для
него программ на машинном языке.
В-вод - клавиатура
Что касается ввода информации в "спектрум", мы будем игнорировать ввод с кассетного
магнитофона и сконцентрируемся на клавиатуре.
Клавиатура - единственный источник информации, предоставляющий связь, в реальном масш-
табе времени. Она может динамически влиять на выполнение любой программы, как операцион-
ной системы в ПЗУ, так и пользовательской программы в памяти с произвольны* доступом.
Логически мы можем рассматривать клавиатуру как двумерную матрицу с восемью рядами и
пятью столбцами, как в приложении а.
Каждое из 40 пересечений представляет клавишу клавиатуры. В нормальном состоянии (ког-
да они не нажаты) каждое пересечение устанавливается равным 1.
При нажатии конкретной клавиши "нажатое" пересечение, соответствующее зтой клавише,
будет сброшено в 0.
Зная связь между клавиатурой и этой внутренней матрицей представления, мы можем вы-
вести логический способ проверки нажатия клавиши, который можно применять в программиро-
вании на машинном языке.
В языке "бейсик" при сканировании клавиатуры нам нужно задать адрес той конкретной по-
ловины ряда клавиатуры, где располагается нужная клавиша, прежде чем использовать функцию
INK.
Аналогичным образом в программе на машинном языке мы должны загрузить в накопитель
значение, соответствующее адресу полуряда клавиш, который мы хотим проверить. Требуемое
значение для каждой половины ряда приводится в самой левой колонке таблицы в приложении
а.
Например, для "н - ENTER" (полуряда) мы загружаем в регистр а значение
LD a, BFH.
Затем значение а будет использоваться для поиска байта, содержащего состояние той
конкретной половины ряда клавиш и возврата в а при задании команды INPUT.
Например^используется порт FEH
Поскольку в половине ряда имеется пять клавиш, нас интересуют только пять младрих би-
тов байта, возвращаемого в регистре а.
Если в этой половине ряда никакие клавиши нажаты не были, то значение пяти младрих би-
тов будет (2**4 + 2**3 + 2**2 + 2**1 + 2**0 т.е. 16 + 8 + 4 + 2 + 1 = 31).
Регистр а = xxxlllll, когда нет нажатых клавиш.
Если мы хотим проверить, нажат ли самый первый бит, то мы проверяем, сброшен ли он.
Есть два способа проверить это:
1. С помощью команды проверки бита, например BIT 0, а если бит сброшен (не установ-
лен), то будет установлен флаг нуля.
2. С помощью команд логического и AND 1 если бит сброшен (не установлен), то результат
бу$ет нулевым и флаг нуля будет установлен.
Первый способ проще, поскольку конкретный бит, подлежащий проверке, указан не-
посредственно в команде проверки бита. Его недостаток состоит в том, что если нам нужно
проверить две клавиши в этой половине ряда, нам придется применять две команды проверки
бита, и, возможно, два относительных перехода.
Например, чтобы проверить биты 0 и 1 с помощью первого способа
BIT 0, a: TEST BIT 0 OF a SET OR NOT
JR Z, NPRESS: JUMP IF NOT PRESSED
BIT 1, a: TEST BIT 1 OF a SET OR NOT
JR Z, NPRESS * JUMP IF NOT PRESSED
DO WHATEVER IF BOTH ARE PRESSED
NPRESS.
TEST BIT 0 OF SET OR NOT - проверить, установлен или нет бит 0 регистра a; JUMP IF NOT
PRESSED - переход, если не нажата; TEST BIT 1 OF SET OR NOT - проверить, установлен или
нет бит 1 регистра a; DO WHATEVER IF BOTH ARE PRESSED - выполнить то, что следует, если
обе клавиши нажаты.
Второй способ проверки с помощью логического и требует несколько больше логических
ухищрений. Для проверки бита 0 мы используем "AND 1 ; для проверки бита 1 - "AND 2"; для
проверки бита 2 - "AND 4" и т.д.
Для проверки двух клавиш мы применяем "AND х", где х - сумм значений, используемых для
проверки каждой из клавиш в отдельности.
Например, чтобы проверить, что бит 0 и бит 1 регистра а установлены:
AND 1: JEST BOTH Bit 0 AND BIT 1 IS SET
cp 1: TEST IF BOTH SET
JK NZ, NBOTH: JUMP IF NOT BOTH PRESSED
TEST BOTH BIT 0 AND BIT 1 IS SET - проверить, что оба бита 0 и 1 установлены; TEST IF
BOTH SET - установлены ли; JUMP IF NOT BOTH PRESSED - переход, если не обе клавиши нажа-
ты.
Чтобы проверить, что установлен один из битов 0 или 1 регистра а.
AND 3: TEST EITHER BIT 0 AND BIT 1 IS SET
JR Z, NOTONE: JUMP IF NOT ONE IS PRESSED
TEST EITHER BIT 0 AND BIT 1 IS SET - проверить, что один из битов 0 или 1 установлен;
JUMP IF NOT ONE IS PRESSED - переход, если ни одна клавиша не нажата.
Приводимая ниже программа на машинном языке показывает способ организации памяти экра-
на в "спектрум":
210040 LD HL,4000Н : LOAD HL WITH START OF DISPLAY FILE
36FF LD (HL).FFH : FILL THET SCREEN LOCATION
110140 LD DE,4fcllH : LOAD DE WITH BYTE IN DISPLAY
010100 LD вс 1 : вс CONTAINS NUMBER OF BYTES то ве : TRANSFERRED
EDB0 LDIR : MOVE a BLOCK LENGTH вс FROM (HL) : то (DE)
C9 RET - : END OF PROGRAM
LOAD HL WITH START OF DISPLAY FILE - загрузить в HL начало файла дисплея; FILL THET
SCREEN LOCATION - заполнить эту ячейку экрана: LOAD DE WITH BYTE IN DISPLAY - загрузить e
DE следующий байт дисплея; вс CONTAINS NUMBER OF BYTES то ве TRANSFERRED в вс содержится
число передаваемых байтов; MOVE a BLOCK LENGTH вс FROM (HL) то (DE) - переместить блок
длиной вс из (HL) в (DE); END OF PROGRAM - конец программы.
Загрузите приведенную выше программу в свой "спектрум" и выполните программу на машин-
ном языке. В том виде, как она написана выше, из (HL) в (DE) будет перемещен всего один
байт.
Теперь давайте изменим четвертую строчку так: LD вс, 31 (01 1F00). Вас, возможно, уди-
вит, какие будут высвечены первые 32 байта на экране. Обратите внимание, вверху экрана
будет проведена очень тонкая полоса. Первые 32 байта экранной памяти относятся к первому
байту каждого из первых 32 символов.
Теперь изменим эту строку так: LD вс, 255 (01FF00). Вновь вы, возможно, удивитесь.
Следующий байт после 32-го.не окажется во втором ряду точек на экране! Зто - первый байт
32- го символа! И так далее вплоть до 256-го символа.
Сможете ли вы предсказать, куда попадет следующий байт? Измените зту строку так: LD
вс, 2047 (01FF07) и выполните программу. Вы обнаружите, что заполненной оказалась только
верхняя треть экрана.
Вы можете поэкспериментировать с этим, пользуясь разными значениями вс вплоть до LD
вс, 6143 (01FF17). Таким способом вы можете посмотреть, как "спектрум" организует экран.
Экранная память на самом пеле разделена на три части.
1. Память с 4000н по 47FFH (===) первые восемь строк.
2. Память с 4800н по 4FFFH === вторые восемь строк.
3. Память с 5000Н по 57FFH (===) третьи восемь строк.
Но не только это, вы еще вспомните, что в "спектрум" каждая литера состоит из восьми
8-битовых байта, что составляет 64 точки.
Например, для литеры "!" Представление имеет вид:
0 00000000 0Н
16 00010000 10Н
16 00010000 10Н
16 00010000 10н
'16 00010000 10н
0 00000000 0н
16 00010000 10Н
0 00000000 0н
Структура памяти экрана дисплея "спектрум" Tamat что первые 256 байтов с 4000Н по
40FFH соответствуют первым сайтам каждой из 256 8-баитовых литер первых восьми строк.
Далее следующие 256 байтов ячеек памяти с 4100н по 42FFH соответствуют вторы* байтам
каждой 256 8-байтовых литер первых восьми строк и т.д.
Таким образом, расположение в памяти восьми байтов, соответствующих первой литере на
экране, будет следующим:
1ST BYTE 4000Н
2ND BYTE 4100н
3RD BYTE 4200Н
4тн BYTE 430Он
5тн BYTE 4400Н
бтн BYTE 4500H
7тн BYTE 4600H
8th BYTE 4700H
1ST BYTE - 1-й байт
Странно, не так ли? Но приходится принимать "спектрум" таким, как его сконструировали.
Сможете ли вы записать восемь байтов, соответствующих 31-й литере третьей строки экра-.
на? Вы можете обратиться к приложению в, карте памяти экрана.
(405ЕН, 415ЕН, 425ЕН.....47SEH)
В соответствии с принятым нами способом выдачи на экран ячеек памяти, соответствующие
первой литере второй группы из восьми строк, будут такими:
4800Н, 4900Н, 4а00н, 4в00н, 4с00н, 4D00H, 4е00н, 4F00H
аналогичным образом, первая литера третьей группы из восьми строк отображается восьмью
байтами в следующих ячейках:
5300Н, 5100Н, 5200Н, 5300Н, 5400H, 5500Н, 5600Н, 5700Н
В применении машинного языка тем не менее, есть определенные преимущества. Очевидные
трудности стоит преодолевать. Вот тривиальный пример из языка "бейсик*, если вы попытае-
тесь выполнить команду PRINT для вводной части экрана ( нижние две строки), то система
"бейсик" этому резко воспротивится. Но на машинном языке у вас имеется полньй доступ ко
всему экрану.
Если вы более внимательно присмотритесь к организации экрана дисплея, вы увидите, что
старший байт первого байта (нй BFB) каждой литеры определяет, к какой из трех групп памя-
ти литера относится.
Например:
если 40н = (H0BFB (41н литера находится в первой
группе из восьми строк
если 48н = (H0BFB (49н литера находится во второй
группе из восьми строк
если 50н = (H0BFB (51н литера находится в третье
группе из восьми строк
Помимо этого три младших бита нов (HIGH ORDER BYTE. Старшего байта) определяют, к ка-
кому из восьми байтов литеры он принадлежит.
Ситуация несколько проясняется? Посмотрите приложение в и постарайтесь понять связь
между ячейками памяти и экраном дисплея.
Рассмотрим следующий пример:
Предположим, нам задан адрес 4а36н. Старший байт адреса будет 4ан, так что:
1) мы знаем, что он находится в пределах памяти экрана дисплея, поскольку его значение
находится между 43н и 58н;
2) его двоичное представление имеет вид 01001010; 3) по младшим трем битам мы знаем, что
он принадлежит третьему байту позиции литеры на экране;
4) если мы сделаем младшие три бита равным нулю, то значение нов будет равно 48н. Таким
образом мы знаем, что он принадлежит второй группе из восьми строк, т.е. средней порции
экрана.
Мы можем прийти к выводу, что заданный байт относится к третьему байту литеры в сред-
ней поруии памяти дисплея.
Какой литере из серединной порции этот байт принадлежит? Для ответа на этот вопрос нам
потребуется знать значение младшего байта адреса.
Мы знаем, что младший байт адреса равен 36н. Так что адрес относится к литере Збн (48
+ 6), т. Е к 54 позиции, считая от первой литеры серединном порции.
Поскольку в каждой строке 32 литеры, заданная позиция находится во второй строке сере-
динной порции экрана дисплея и будет (54 - 32 + 1) - и литерои в этой строке.
Вывод, который мы можем сделать, - заданный байт является третьим байтом 23-й литеры
10-й строки от начала экрана.
Атрибуты телевизионного экрана
Память, предназначенная для хранения атрибутов экрана, легче для понимания, чем сама
память дисплея, госкольку у нее имеется взаимно однозначное соответствие с литерами дисп-
лея.
Файл атрибутов расположен в памяти с 5800н и 5AFFH. Он содержит 768 байтов, что соот-
ветствует 24 строкам по 32 литеры каждая. Иными словами, имеется по одному байту - атри-
буту для каждой позиции литеры.
Так, 5800н соответствует атрибуту первой литеры первой строки, 5801н - второй литеры,
5802н - третьей,..... 581FH тридцать второй литере первой строки.
№ знаем, что для каждой позиции литеры на экране имеется соответствующий байт-атрибут
а памяти атрибутов, составленный следующим образом:
байт-атрибут
биты 0 -2 представляет цвет чернил от 0 до 7.
Биты 3 -5 представляет цвет бумаги от 0 до 7
бит 6 повышенная яркость- если 1, нормальная- если 0
бит 7 мигание - если 1, отсутствие мигания - если 0
Упражнение
Сможете ли вы написать подпрограмму, преобразующую заданный адрес на экране в адрес
соответствующего ему атрибута. Например, 4529н.
По существу вам нужно определить, какой литере экрана соответствует этот адрес, а за-
тем прибавить это значение к 5800н.
Приводимая ниже программа показывает, как этого достичь быстро.
LD HL, 4529н: загрузить заданный адрес в HL
LD а. н: загрузить старший байт в а
AND 18н: ловушка для битов 3 и 4 для определения
: того, какой части экрана соответствует
: адрес
SRA а: сдвиг накапливающего регистра вправо
SRA а: три раза, т.е. Деление на 8
SRA а: результат может быть равен 0, 1 или 2
: в зависимости от того, чему равнялся н:
: 48н, 50н или 50н (так в оригинале, оче-
видно, опечатка iпримеч. Пер. ))
ujd з, 58^-' преобразование в память атрибутов
и, а' в - адрес атрибута, т. Е н = 58н, 59н или
• 50ч. L остается неизменным!!!
Звуковой сигнал
Еще одно средство связи в реальном масштабе времени, предоставляемое вашей мико-ЭВМ
:п9ктрум" - звуковой сигнал, Было бы глупо не воспользоваться этим средством в полной
В машинном языке "спектрум" есть два основных способа генерирования звука.
1. Посылка сигналов на выходной порт 254 для кассетного магнитофона в течение опреде-
ленного промежутка времени с помощью команды OUT 254.
Например, OUT (254), а
2. Установить определенные значения в HL, DE и вызвать программу звукового сигнала из
"ЗУ для генерации сигнала.
Входные параметры:
DE - продолжительность в секундах * частота
ril " (437 506 / частота) - 30, 125
потом
CALL 03в5н
Преимуществом первого способа генерации звука является отсутствие обращений к ПЗУ. Он
выполняется более быстро, но...
Поскольку АДУ (в оригинале ULA) постоянно обращается к первым 16к памяти с произволь-
ном дои«умом для выполнения вывода на экран, ваша программа, если она размещена в первых
:<' оудет часто подвергаться кратковременным прерываниям.
lcah программа генерирует звуковой сигнал, то звук будет издаваться в виде непредска-
,емых по продолжительности гудков. Один из способов преодоления этой трудности состоит в
еремещении той части программы, которая генерирует звук, в область больших значений ад-
ресов памяти, если у вас ЗВМ с объемом памяти 48к.
Если же у вас нет ЗВМ с объемом памяти 48к, то вы все-таки можете генерировать звук
лим методом, но это не будет "чистый звук". Вам придется применять второй способ генера-
.ии звука (с помощью вызова программы из ПЗУ), чтобы добиться нужного результата.
Обратите внимание, что при посылке значений на порт вывода 254 они будут также влиять
-а ^вет окаймления, и включать MIC, а также громкоговоритель, в зависимости от посылаемо-
"0 значения.
С другой стороны, программа из ПЗУ для генерирования звука по Существу позволяет вам
применять из своей программы на машинном языке команду веер. Вы мо^те считать, что в па-
ре регистров содержится значение продолжительности звукового сигнала, а в HL - значение
частоты. Поэкспериментируйте с различными значениями HL и DE, пока не получите нужный вам
звук.
Ограниченность этого метода, конечно, состоит в том, что вы не можете выйти за пределы
гсго диапазона звуков, которые дает возможность издавать команда веер.
Ввеление в мониторные программы на машинном языке