Как выполнить программу на машинном языке
"ZX спектрум" на самом деле все время выполняет программы на машинном язьке! (Когда он
включен). Просто вы об этом не знаете даже когда вы ничего не делаете, просто смотрите на
экран, пытаясь придумать, что ввести в качестве первой строки вашей потрясающей основы
программы на языке бейсик", ЗВМ "спешум" занята работой под управлением программы на
машинном языке.
Зто одна из программ, хранимых в ПЗУ, и ее называют "операционной системой". Например,
часть программы, выполняющаяся, когда вы просто сидите и смотрите на экран, выполняет
следующее:
сканирует клавиатуру в поисках введенной информации;
отмечает, что ни одна клавиша не нажата;
выдает на дисплей текущий экран (пустой).
Даже когда вы выполняете программу на языке "бейсик", ЦП управляется программой на ма-
шинном языке. Как мы уже обьясняли, эта программа относится к типу "интерпретаторов": она
берет вашу следующую команду языка "бейсик", преобразует ее на машинный язык, выполняет
эту часть программы-и затем воввращается к интерпретации следующей команды.
Все это оказывается не так, когда вы выполняете свою собственную программу на машинном
языке!
Полная свобода от операционной системы! Применение функции "USR" передает управление
ЦП тем командам, которые вы поместили по адресу USR, каковы бы они ни были. Что бы там ни
оказалось, он будет интерпретировать это как допустимые команды машинного языка.
Перспектива довольно пугающая, ведь при потере управления вы можете потерять все, что
f хранилось в памяти. Одна ошибка, один неверный символ, и вам придется выключать "спект-
рум" и вновь начинать сначала.
Нет ни сообщений об ошибках, показывающих, где вы ошиблись, ни синтаксической проверки
неверных предложений - так что если вы сделаете малейшую ошибку, будут потеряны часы ро-
боты, затраченные на ввод вашей программы!
В конце этой книги мы включили программу на языке "бейсик", которая позволит вам вво-
дить и редактировать программы на машинном языке. Введя эту программу в ваш "спектрум",
запишите ее на ленту, поскольку более чем вероятно, что вы по крайней мере однажды поте-
ряете управление вашей программой на машинном языке.
С другой стороны, не бойтесь экспериментировать - вы не сможете-испортить ЭВМ какой бы
то ниоыло программой на машинном языке, вводимой вами. Самое худшее, что может произой-
ти, - вам придется выключить и вновь включить ваш "спектрум".
Сейчас мы вам для возбуждения аппетита дадим очень^простую программу на машинном язы-
ке. Загрузите написанную на языке "бейсик" программу "редактор машинного языка в коде
EZ" найденную в конце этой книги, и выполните ее.
Программа запросит у вас адрес загрузки. Зто значит спросит у вас, где бы вы хотели
разместить машинные команды. В этой программе кода вы не можете применять адреса менее
3150 0, так что давайте выберем 32000. Введите число 32000, затем нажмите (ENTER).
На экране теперь светится: команда или строка (#*#):
это означает, что программа ждет, чтобы вы ввели команду или новую строку текста ма-
шинной программы.
Давайте введем "1", затем пробел, затем "с" и затем "9". Зто похоже на ввод строки
языка "бейсик" с номером строки 1, но это - строка машинного языка. Если все в порядке,
то нажми (ENTER). На экране теперь должны быть показаны все введенные вами строки:
1 с9 и внизу экрана - подсказка 'команда или строка (ИМ):
на этом этапе вы не хотите добавлять больше строк, так что давайте вместо этого введем
команду.
Введите слово "DUMP" и затем нажмите (ENTER). Действие этой команды состоит в выдаче
текста машинной программы в виде распечатки по указанному вами адресу, а именно 32000.
Вас можно поздравить, вы только что ввели команду программы на машинном языке! Вы мо-
жете проверить, что она была введена правильно, введя теперь команду "MEM" и затем
(ENTER). Зта команда позволяет вам просмотреть содержимое памяти, и она запросит у вас
начальный адрес. Введите тогда 32000 и затем (ENTER).
Вы увидите-содержимое ячеек памяти с 32000 по 32087. Во всех должно быть 00, за исклю-
чением 32000, в которой должно быть с9. Затем нажмите клавишу "м", чтобы вернуться на
этап ввода основной команды.
Команда "с9" означает RETURN (возврат) !
Все это несколько напоминает езду на велосипеде в первый раз: вы действительно хотите
получить самостоятельность, но как только немного проедете, хочется вернуться" к надеж-
ности твердой земли под ногами (иньми словами, операционной системы)
Теперь переходим к выполнению программы на машинном языке. Чтобы выполнить любую прог-
рамму на машинном языке, записанную вами в память, введите команду "RUN" и затем (ENTER).
Что происходит? Почему внизу экрана появилось число 32000? Зто - адрес, использованньй
вами в качестве адреса загрузки в начале.
Не забывайте, что функция "USR" состоит в выполнении подпрограммы на машинном языке. В
частности из этой функции вытекает, что значение USR при возврате из программы на машин-
номязыке, помещенной вами в память, будет равно значению пары регистров ВС.
Ответ на этот вопрос вытекает из способа^ которым операционная система "спектрум" (да,
все та же самая) обращается с функцией "USR .
Когда операционная система встречает функцию "USR", она загружает указанный пользова-
телем адрес в пару регистров ВС - в данном случае 32000.
Значение "USR", как в предложении
LET а = USR 32000 естественно, приводит к ответу 32000!
Зта особенность функции "USR будет очень полезна, поскольку она позволит нам следить
за тем, что происходит во время выполнения программы на машинном языке.
Давайте введем следующую программу на машинном языке:
0В
с9
ввести эту короткую, состоящую из двух команд, программу можно так.
Ввести строку 1, введя Т, затем пробел, затем "0 , затем "в" и затем нажав (ENTER).
Аналогичным образом ввести строку 2 с9. Распечатка должна показатьевам, что вы ввели
строки правильно. Введите команду "DUMP" и затем команду " RUN"
На этот раз результат равен 31999! Так получилось потому, что команда "0в" - это "DEC
ВС" (сокращенное название для уменьшения значения вс на 1).
Вилы алрссадии в ZX SPECTRUM:
непосредственная адресация;
регистровая адресация;
косвенная регистровая адресация;
расширенная адресация;
индексная адресация.
Приведенный выше списбк не покрывает все возможные комбинации - только те, которые от-
носятся к числам для одного регистра. Давайте поочередно рассмотрим каждое из этих воз-
можных видоизменений.
Непосредственная адресация
общая форма для нее имеет вид
LD Rj, N (или иная команда - мы используем L0 только в качестве пдимера мы используем
сокращение "R для обозначения произвольного 8-битового регистра, a N" - для 8-битового
числа.
Непосредственная адресация - зто метод, использующий только один регистр. Реальные
данные входят составной частью в команду; зто означает, что ЦП может выполнять команду
непосредственно после ее получения. Ему не приходится вести поиск дополнительной информа-
ции в памяти, чтобы выполнить эту команду.
Обычно мы применяем непосредственную адресацию для инициализации счетчиков и определе-
ния констант, необходимых для вычислений.
Непосредственную адресацию легко применять в программировании на машинном язьке. Тем
не менее, зто - наименее гибкий из всех методов передачи информации (способов адресации),
поскольку и регистр, и данные фиксируются в момент написания программы. Эквивалентное
предложение на языке "беисик" выглядело бы так: LET а=5 очевидно, команды такого типа не-
обходимы, но мы не могли бы писать таким способом программы целиком!
Регистровая адресация • '
Мы уже кратко рассматривали этот способ'. Общий форма имеет вид
(или другие команды) при этом методе участвуют только 2 регистра, г
ЦП допускает передачу информации между любыми двумя регистрами, за исключением руки
Для команд с регистровой адресацией требуется всего один байт.
Команды этого типа не только коротки (один байт), 'они также и быстрее выполняются.
Требующееся для их выполнения время составляет 4 импульса генератора синхросигналов, или
менее 1 микросекунды для "спектрум".
Для написания программ на машинном язьке существует "правило", что для повышения эф-
фективности программы в плане затрат времени и памяти всегда, когда есть возможность,
следует применять передачу информации регистр - регистр.
Косвенная регистровая адресация
LO (RR), а или LO a, (RR)
LD (HL), N
Этот богатый возможностями тип команды приводит к передаче данных между ЦП и ячейкой
памяти, на которую указывает содержимое одной из 16-битовых пао.
Косвенная регистровая адресация действует быстрее, чем обычная косвенная адресация,
поскольку ЦП нет необходимости извлекать адрес из памяти.
Тем не менее, мы должны сначала загрузить регистр, так что косвенная регистровая ад*
ресация дает преимущества только тогда, когда программа использует один и тот же или
соседние адреса многократно.
Например, LD HL, SHAPE: заг^зить начало базы данных
LOOP LD a. (HL): поиск данных
INC HL: дать приращение указателю
продолжать LOOP пока не кончится
Расширенная адресация
LD a, (NN) или LD (NN), а
Теперь посмотрим, как происходит обмен информацией между памятью и регистрами.
При расширенной адресации команда программы предоставляет ЦП адрес-, заданный двумя
байтами. Если передача информации осуществляется в или из накапливающего регистра, то она
повлияет только на содержимое ячейки памяти, заданной двухбайтовым целым числом.
Если же передача информации осуществляется в или из пары регистров, то она повлияет и
на ячейку памяти, заданную двухбайтовым целым числом, и на следующую ячейку.
Команда такого типа имеет следующий формат:
байт 1 код операции
байт 2 (допустимый дополнительный код операции)
байт 3 младшие разряды 16-битового целого числа
байт 4 старшие разряды этого целого числа
Именно таким способом программа может считывать содержимое памяти в регистры пользова-
теля. И вновь здесь требуется абсолютный адрес, иными словами, в результате применения
этого типа адресации программа может оказаться неперемещаемой, за исключением случаев,
когда перемещаемым оказывается абсолютный адрес, на который ссылается команда.
SHAPE DB N, N, N..... : База данных SHAPE
LD a, (SHAPE): загрузить первый байт в
накапливающий регистр
Индексная адресация
LD R, (IX/IY+д) или LD (IX/IY+д), R
(или другие команды)
В передаче информации такого типа участвует индексный регистр IX или IY.
ЦП складывает содержимое индексного регистра с адресом, заданным в команде, чтобы най-
ти исполнительный адрес.
Зто - один из типов команд Z80, имеющих 16-битовый код операции. Другой широко приме-
няемый 16-оитовый тип команды - команда загрузки блока, например, LDIR (LOAD INCREMENT
AND REPEAT- загрузить, дать приращение и повторить)
Одно из типичных применении метода адресации такого типа - выполнение табличных опера-
ций.
Индексный регистр может поменяться как указатель на начало таблицы данных. Значение
смещения задается в команде, чтобы определить адрес требуемого элемента таблицы, к кото-
рому нужно обратиться программе; например, LD IX, TABLESTART : инициализировать указатель
на начало таблицы
LD a, (IX+3): обратиться к третьему байту от начала таблицы
команда этого типа имеет следующий формат:
байт 1 (код операции)
байт 2 (код операции)
байт 3 D: целочисленное значение смещения
Число "D" - 8-оитовое число, которое необходимо задавать вместе с командой, и оно не
может быть переменным. Зто означает, что диапазон адресации ограничен значениями от -128
до 127 считая от адреса, заданного индексным регистром.
Индексная адресация выполняется медленнее, поскольку ЦП для получения исполнительного
адреса должен выполнить сложение. И все-таки индексная адресация гораздо гибче, поскольку
с помощью одной и той же команды можно обрабатывать все элементы массива или таблицы.
Таблица
команды операций загрузки для одного регистра
MNEMONIK BYTES TIME EFFECT ON FLAGE
TAKEN с Z PV S N н
LD REGISTER, REGISTER 1 4 ---------
LD REGISTER, NUMBER 2 7 ---------
LD a. (ADDRESS) 3 13 ------
ld (Address), а з 13 ------
LD REGISTER, (HL) 1 7 ------
LD a, (bc) 1 7 ------
LD a DC) 1 7 ------
LD CftL , REGISTER 1 7 --- ---
LD (bc), a 17 - .....
LD (DE), a 17 ------
LD REGISTER, (IX+д) 3 19 --- ---
LD REGISTER. (IY+д) 3 19 --- ---
ld jix+д), Agister з 19 ------
LD (IY+д), REGISTER 3 19 --- ---
LD (HL), NUMBER 2 10 ------
LD IX+д), NUMBER 4 19 ------
LD (IY+д); NUMBER 4 19 --- ---
WEMONIC-мнемоническое обозначение; BYTES-количество байтов; TIME TAKEN-затрачиваемое
время; EFFECT ON FLOGE-состояние флагов после выполнения; REGISTER-.регистр;- NUMBER-
число; ADDRESS-адрес.
Обозначения для флагов:
t - указывает, что флаг меняется в результате операции;
0 - указывает, что олаг сброшен;
1 - указывает, что олаг установлен;
- - указывает, что Флаг остается неизменным.
Остановимся подробнее на некоторых способах передачи информации.
LD а, в
LD н, е
и Т-Д-
Напомним используемую терминологию: LD означает загрузить . , Означает в" и ко-
манда в мнемоническом виде (сокращенном) читается как русское предложение, но с обратным
юрядком операндов. (В оригинале, в соответствии с нормами английского языка говорится о
прямом порядке операндов.
Таким образом, вслух такую, например, команду, как
LD а, в мы прочитали бы "загрузить в В А ". Д следующий пример читался бы как "загру-
1ить Е в Н".
Второй способ рассмотрим на примере:
LD D, D7
(D7 - шестнадцатеричное представление 215)
в данном случае в регистр D засылается число 215.
Возможно, вы помните, что зто называется непосредственной адресацией. (Название доста-
точно очевидное, не правда-ли?
Опять-таки, вы можете проделать зто с любыми регистрами и любыми числами. Ограничени-
ем, конечно, служит размер числа, которое можно задать с помощью 8 битов: от 0 до 256.
Краткая запись такой операции имеет вид "LD R, N , где "(?" обозначает произвольный ре-
гистр, a "N" - любое число. Здесь по-прежнему действует ранее введенное условное обозна-
чение 8 битов одной буквой.
Пример "внешней адресации":
LD а, Ш) загрузить содержимое ячейки NN в а.
Допустима и обратная команда. Зто - одна из обращающих на себя внимание особенностей
Z80 - в наборе команд имеется симметрия.
LD (NN), а
обязательно обратите внимание, что зти команды допустимы только для регистра а .
Давайте задержимся здесь на наносекунду и посмотрим, что эти две команды на самом деле
нам дают.
Во-первых, диапазон значений чисел, задаваемых числом для 2 регистров (NN), будет от 0
до 65 535. Зто 64к, то есть с помощью этой команды можно получить доступ не более чем 64к
памяти! Зто значит, что вся память: ПЗУ, программа, дисплей свободная память - должна
уместиться в 54 к. В "16к спектрум" на самом деле 16к используются ПЗУ и 16к - памятью с
произвольным доступом, что вместе составляет 32к. 16К относится только к памяти с произ-
вольным доступом. В "48к спектрум' имеются теже самые 15к ПЗУ плюс 48к памяти с произ-
вольным доступом, что вместе составляет 64к. Поэтому для Z80 невозможно получить доступ к
большому количеству памяти, чем "48к спектрум".
Команда LD a, (NN), читаемая как "загрузить содержимое ячейки NN в а" - очень богата
возможностями. Она позволяет нам читать содержимое любой ячейки памяти, будь то ПЗУ, или
память с произвольным доступом.
Вы можете использовать эту команду для исследований по вашему вкусу, даже для тех яче-
ек, где память отсутствует, например, попытаться посмотреть, что находится за пределами
32к памяти, даже если у вас нет дополнительной памяти. Вас ждет сюрприз - там вовсе не
везде нули!
Обратная команда "LD (NN), а", которая читается как - "загрузить а в ячейку памяти
NN", будет пытаться вести запись также в любую ячейку памяти, но для нее сказьваются фи-
зические ограничения.
Вы не можете вести запись в ячейки, которые не могут содержать эту информацию, подобно
несуществующей памяти за пределами размера вашей системы.
Одно из свойственных этой команде ограничений состоит в том, что вам необходимо во
время написания программы знать, какую ячейку памяти мы хотим проверять или записать в
нее.
Сокращение "NN" означает определенное число, например, 17 100 а не переменную.
Вы не можете использовать эту команду в эквиваленте циклу "FOR - NEXT" на машинном
языке. Поэтому основное применение этой команды - отведение конкретных ячеек памяти под
хранение переменных;
А что если мы не знаем точный адрес ячейки памяти, где мы должны искать информацию?
Предположим, мы можем только посчитать, где эта информация должна находиться ? Поскольку
нам необходимо 16 битов, чт о б ы задать адрес произвольной ячеики памяти, нам придется хра-
нить его в 16-битовом реглтре т.е. в одной из пас регистров вс, DE или HL, или в одном
из индексных регистров IX или iY.
Один из способов для этого - сделать так, чтобы в одной из пэр регистров содержался
адрес ячейки памяти. Поскольку информация содержится в регистре и нам не дан адрес не-
посредственно, мы называем эту форму адресации косвенной регистровой адресацией.
Мнемоническое сокращение для таких команд имеет вид
LD R, (HL)
LD а (вс)
LD a, (DE) по-русски эти команды читаются так:
"загрузить в регистр содержимое ячейки памяти, на которую указывает HL"
"загрузить з а содержимое ячейки памяти, на которую указывает вс"
"загрузить в а содержимое ячейки памяти, на которую указывает DE*
Обратите внимание, что, используя "HL" в качестве указателя на нашу ячейку памяти, мы
можем провести загрузку в любой регистр, даже в н или L, хотя это и звучит странно, но
что, применяя вс или DE, мы можем загрузить только в регистр а. Так происходит потому,
что пара регистров HL привилегированна точно так же, как привилегирован регистр а.
И здесь также имеется симметрия по отношению к этим командам, и мы можем аналогичным
образом загружать информацию в ячейки памяти:
LD (вс),' а
LD (DE), а это также называется "косвенной регистровой адресацией" вне зависимости от
того, в каком направлении перемещается информация.
С другой стороны, мы могли бы применить индексные регистры IX и IY для указания ячейки
памяти. Краткая запись этих команд имеет вид:
LD R, (IX + д)
LD R, (IY + д) где "R - опять произвольный регистр, ад- смещение относительно
адреса, на который указывает IX или IY. (Не спутайте обозначения "д" - мы имеем ввиду Не
регистр "О" а "д = смещение (DISPLACEMENT)).
Число "д - 8-битовое число, которое нужно указывать во время программирования и нель-
зя сделать переменным. В этом - слабость данной конкретной команды, .и это означает, что
ее применение обычно ограничивается чтением и записью таблиц, содержащих данные.
Имеется также симметричная команда:
LD IX + д , R
LD (IY + д), R
Если этот конкретный способ адресации выглядит несколько усложненным, не беспокойтесь,
вам он вряд ли понадобится в нескольких первых ваших программах.
Чип Z80 в ЗВМ "синклер" в высшей степени универсален, и вы можете комбинировать разные
способы загрузки чисел, описанных нами выше.
Например,-вы можете комбинировать непосредственную адресацию (т.е. задание числа, ко-
торое вы хотите загрузить) с внешней адресацией (т.е. задание адреса загрузки с помощью
пары регистров).
Зто называется "непосредственной внешней адресацией".
К сожалению вы можете использовать только пару регистров HL и поэтому сокращенная за-
пись имеет вид:
LD (HL). N
Зто удобно, поскольку вы можете непосредственно заполнить ячейку памяти без необходи-
мости сначала загрузить это значение в регистр.
Возможна аналогичная комбинация с индексными регистрами, она называется "не-
посредственная индексная адресация". Зта команда используется более ограниченно,-и сокра-
щенная форма таких команд имеет вид:
LD (IX+ д), N
LD (IY+ д), N
Применение этих команд в программе на машинном языке.
Давайте попробуем на практике применить некоторые из этих команд "LD".