Код
Команда
8B
ADC A,E
9B
SBB A,E
8C
ADC A,H
9C
SBB A,H
8D
ADC A,L
9D
SBB A,L
8E
ADC A,[HL]
9E
SBB A,[HL]
8F
ADC A,A
9F
SBB A,A
Допустим, в аккумуляторе записан байт 35h, а в регистре B —
байт 22h. После выполнения команды:
SUB A,B
аккумулятор содержит байт 13h.
Если в регистре А записан байт 35h, в регистре H — 10h, в
регистре L — 7Ch, а в ячейке памяти по адресу 107Ch — байт
4Ah, то выполнение команды:
ADD A,[HL]
приведет к сложению содержимого аккумулятора (35h) и со-
держимого ячейки памяти, адресуемой парой регистров H и L,
т. е. 4Ah. Результат (7Fh) будет помещен в аккумулятор.
С помощью команд ADC и SBB микросхема 8080 способна
складывать и вычитать числа, разрядность которых равна 16,
24, 32 и т. д. Например, если два 16-битовых числа записаны в
пары регистров BC и DE, то для их сложения и помещения
результата в пару регистров ВС вам понадобится такая после-
довательность команд:
MOV A,C
; Младший байт
ADD A,E
MOV C,A
MOV A,B
; Старший байт
ADC A,D
MOV B,A
Для сложения используются две команды: ADD для младшего
байта и ADC для старшего. Бит переноса, который может по-
явиться в результате первого сложения, учитывается при вто-
ром сложении. Одно из слагаемых всегда обязательно распо-
лагается в аккумуляторе, поэтому даже в такой короткой про-
(продолжение)
333
Два классических микропроцессора
грамме команда MOV используется четырежды. Вообще в про-
граммах для 8080 команды MOV всегда представлены в изо-
билии.
Настало время поговорить о флажках процессора 8080. В
главе 17 мы использовали два флажка — переноса и нуля. В
микросхеме 8080 их на 3 больше — добавляются флажки зна-
ка (Sign), четности (Parity) и вспомогательного переноса
(Auxiliary Carry). Для хранения всех флажков предназначен
особый 8-битовый регистр — слово состояния программы
(Program Status Word, PSW). Команды LDA, STA и MOV на зна-
чения флажков не влияют. Команды ADD, SUB, ADC и SBB
изменяют значения флажков следующим образом.
•
Флажок знака устанавливается в 1, если старший бит ре-
зультата равен 1 (результат отрицателен).
•
Флажок нуля устанавливается в 1, если результат равен 0.
•
Флажок четности устанавливается в 1, если результат че-
тен, т. е. четно число 1 в двоичном представлении резуль-
тата. В 0 флажок четности устанавливается, если результат
нечетен. Проверку четности иногда используют для конт-
роля корректности результата, хотя в программировании
8080 этот флажок практически не применялся.
•
Флажок переноса устанавливается в 1, если выполнение
команды ADD или ADC привело к переносу, а также если
выполнение команды SUB или SBB не привело к его появ-
лению (в компьютере из главы 17 поведение флажка пере-
носа подчинялось другим правилам).
•
Флажок дополнительного переноса устанавливается в 1,
если выполнение команды DAA (о ней чуть позже) приве-
ло к переносу из младшей тетрады в старшую.
С помощью двух команд значение флажка переноса можно
изменить непосредственно:
Код
Команда Действие
37
STC
Установить флажок переноса в 1
3F
CMC
Заменить значение флажка его дополнением
В дополнение к арифметическим командам ADD, ADC, SUB
и SBB, которые были доступны и компьютеру из главы 17 (хотя
и не с той степенью гибкости), процессор 8080 способен вы-
334
Глава девятнадцатая
полнять и логические операции И, ИЛИ и «Исключающее
ИЛИ». Как арифметические, так и логические операции вы-
полняются в арифметико-логическом устройстве процессора.
Код
Команда
Код
Команда
A0
AND A,B
B0
OR A,B
A1
AND A,C
B1
OR A,C
A2
AND A,D
B2
OR A,D
A3
AND A,E
B3
OR A,E
A4
AND A,H
B4
OR A,H
A5
AND A,L
B5
OR A,L
A6
AND A,[HL]
B6
OR A,[HL]
A7
AND A,A
B7
OR A,A
A8
XOR A,B
B8
CMP A,B
A9
XOR A,C
B9
CMP A,C
AA
XOR A,D
BA
CMP A,D
AB
XOR A,E
BB
CMP A,E
AC
XOR A,H
BC
CMP A,H
AD
XOR A,L
BD
CMP A,L
AE
XOR A,[HL]
BE
CMP A,[HL]
AF
XOR A,A
BF
CMP A,A
Команды AND, OR и XOR выполняются побитово, т. е. дей-
ствуют независимо на каждую пару битов. Например, после
выполнения команд:
MVI A,0Fh
MVI B,55h
AND A,B
содержимое аккумулятора будет равняться 05h. Если бы пос-
ледняя команда была OR, в аккумулятор было бы записано
число 5Fh. Наконец, результатом команды XOR стало бы чис-
ло 5Ah.
Действие команды CMP (Compare, сравнить) аналогично
действию команды SUB с единственным исключением — ре-
зультат не сохраняется в аккумуляторе. Иначе говоря, коман-
да CMP вычитает одно число из другого и тут же забывает ре-
335
Два классических микропроцессора
зультат. В чем ее смысл? Во флажках! Они расскажут вам об
отношениях между числами, которые вы сравниваете. Рассмот-
рим в качестве примера команды:
MVI B,25h
CMP A,B
После их выполнения содержимое аккумулятора не изменит-
ся. Но если оно равно 25h, будет установлен флажок нуля, а
если оно меньше 25h — флажок переноса.
У восьми арифметических и логических команд имеются
также версии для работы непосредственно с байтами.
Код
Команда
Код
Команда
C6
ADI A,xx
E6
ANI A,xx
CE
ACI A,xx
EE
XRI A,xx
D6
SUI A,xx
F6
ORI A,xx
DE
SBI A,xx
FE
CPI A,xx
Так показанную выше пару команд можно заменить одной:
CPI A,25h
Еще две команды для работы с аккумулятором:
Код
Команда
27
DAA
2F
CMA
Команда CMA (Complement Accumulator, дополнить акку-
мулятор) вычисляет дополнение содержимого аккумулятора
до 1 — все нули превращаются в единицы, а все единицы — в
нули. Если до выполнения команды CMA в аккумуляторе за-
писано число 01100101, то после в нем будет число 10011010.
Дополнение аккумулятора до 1 вычисляет также команда:
XRI A,FFh
Команда DAA (Decimal Adjust Accumulator, десятичная кор-
рекция аккумулятора) — вероятно в наборе команд 8080 са-
мая сложная. Ее выполнением в микропроцессоре занимается
специально предназначенное для этого устройство.
336
Глава девятнадцатая
Команда DAA помогает программисту осуществлять ариф-
метические операции с десятичными числами, представлен-
ными в кодировке BCD (binary-coded decimal, десятичное в
двоичной кодировке). В данных, закодированных с помощью
BCD, каждая тетрада может принимать значения только от 0000
до 1001, символизирующие десятичные цифры от 0 до 9. В
формате BCD 8 битов байта используются для хранения двух
десятичных цифр.
Допустим, в аккумуляторе хранится BCD-значение 27h,
соответствующее десятичному числу 27 (в обычной ситуации
шестнадцатеричное число 27h равно десятичному 39), а в ре-
гистре В — BCD-значение 94h. После выполнения команд:
MVI A,27h
MVI B,94h
ADD A,B
аккумулятор будет содержать число BBh, которое, конечно, не
может быть числом в формате BCD, так как обе его тетрады
превышают 1001. Вот тут-то на помощь и приходит команда
DAA. После ее выполнения в аккумулятор записывается чис-
ло 21h и устанавливается флажок переноса, поскольку в деся-
тичном исчислении 27 + 94 = 121. При работе с BCD-арифме-
тикой команда DAA очень полезна.
При программировании довольно часто возникает необ-
ходимость прибавить к числу 1 или вычесть из него 1. Напри-
мер, в программе умножения из главы 17 нам нужно было
вычитать 1 из числа, для чего мы складывали его с FFh, т. е. с
дополнением до 2 числа –1. В наборе команд 8080 для умень-
шения или увеличения на 1 числа в регистре или ячейке памя-
ти предусмотрены специальные команды.
Код
Команда
Код
Команда
04
INR B
05
DCR B
0C
INR C
0D
DCR C
14
INR D
15
DCR D
1C
INR E
1D
DCR E
24
INR H
25
DCR H
2C
INR L
2D
DCR L
337
Два классических микропроцессора
34
INR [HL]
35
DCR [HL]
3C
INR A
3D
DCR A
Они действуют на все флажки, кроме флажка переноса.
В набор команд 8080 входят четыре команды циклического
сдвига (rotate), сдвигающие содержимое аккумулятора на 1 бит
влево или вправо.
Код
Команда Действие
07
RLC
Сдвинуть аккумулятор влево
0F
RRC
Сдвинуть аккумулятор вправо
17
RAL
Сдвинуть аккумулятор влево через разряд
переноса
1F
RAR
Сдвинуть аккумулятор вправо через разряд
переноса
Из всех флажков они действуют только на флажок переноса.
Допустим, аккумулятор содержит число A7h, или 10100111
в двоичном представлении. RLC сдвигает биты влево. Самый
старший бит («выталкиваемый» из числа «сверху») становит-
ся самым младшим и определяет состояние флажка переноса.
В данном случае в результате сдвига получится число 01001111,
а флажок переноса будет установлен в 1. RRC таким же обра-
зом сдвигает число вправо. Результат ее действия на число
10100111 будет равен 11010011, флажок переноса также будет
установлен в 1.
Команды RAL и RAR действуют немного иначе. RAL сдви-
гает содержимое аккумулятора влево, записывает во флажок
переноса содержимое старшего бита аккумулятора, а преды-
дущее значение флажка переноса записывает в младший бит
аккумулятора. Например, если аккумулятор содержит число
10100111 и флажок переноса равен 0, то после выполнения RAL
в аккумуляторе будет записано число 01001110, а флажок пе-
реноса равен 1. При тех же начальных условиях команда RAR
приведет к установке флажка переноса в 1 и записи в аккуму-
лятор числа 01010011.
Команды сдвига очень удобны при умножении или деле-
нии числа на 2, что соответствует сдвигу влево или вправо.
(продолжение)
338
Глава девятнадцатая
Память, к которой обращается процессор, называется па-
мятью с произвольным доступом не случайно. Для обращения
к любой ячейке памяти процессору достаточно указать ее ад-
рес. Память RAM подобна книге, которую можно открыть на
любой странице, в отличие от недельной подшивки газет на
микропленке. Чтобы добраться до субботнего выпуска, надо
промотать пленку за большую часть недели. Такие устройства
(микропленки, магнитофонные ленты и т. п.) называются ус-
тройствами с последовательным доступом (sequential access).
Однако временами удобнее оказывается запоминающее
устройство, доступ к которому нельзя назвать ни произволь-
ным, ни последовательным. Рассмотрим такую жизненную
ситуацию. Вы — самый младший служащий в фирме, которо-
му все вышестоящие работники дают поручения, складывая
на стол папки с документами, с которыми что-то нужно сде-
лать. Порой вы обнаруживаете, что не можете продолжить
работу с одной папкой, пока не обработаете другую, связан-
ную с ней папку. Вы кладете первую папку на стол, а вторую
раскрываете поверх нее. Но вот к вашему столу приближается
начальник и передает вам третью папку, работу над которой
нужно закончить срочно. Вы, естественно, располагаете ее по-
верх предыдущих двух. Но вот беда — для выполнения зада-
ния вам нужны документы из еще одной папки, и вот стопка
на столе состоит уже из четырех папок…
Если задуматься, то по этой стопке легко можно отследить
все выполняемые вами задания. Сверху лежит самая важная
папка. Закончив работу с ней, вы обращаетесь к следующей
папке и т. д. Покончив с самой нижней папкой (с нее вы нача-
ли рабочий день), вы вправе отправляться домой.
С технической точки зрения такой способ хранения инфор-
мации называется стеком (stack). «Стопка» информации растет
снизу вверх и убывает сверху вниз. Данные в стеке организова-
ны по принципу «последним вошел — первым вышел» (Last In
First Out, LIFO). То, что было помещено в стек в последнюю
очередь, первым извлекается из него. То, что было помещено в
стек в первую очередь, извлекается из него последним.
В компьютерах стек используется, конечно, не для хране-
ния бумаг, а для хранения чисел, что, впрочем, не менее удоб-
но. Помещение информации в стек называется «вталкивани-
ем» (push), а ее извлечение — «выталкиванием» (pop).
339
Два классических микропроцессора
Допустим, вы пишете на языке ассемблера программу, дан-
ные для которой хранятся в регистрах А, В и С. На каком-то
этапе вы замечаете, что для выполнения очередного расчета
вам нужно использовать эти регистры, а затем восстановить в
них исходные значения.
Конечно, ничто не мешает вам сохранить числа из регист-
ров в ячейках памяти, а затем вернуть их из памяти обратно в
регистры. Но при этом придется следить за тем, в каких ячей-
ках оказались эти числа, чтобы случайно не записать поверх
них другую информацию. Гораздо безопаснее на время поме-
стить («втолкнуть») числа в стек:
PUSH A
PUSH B
PUSH C
Суть действия этих команд я объясню чуть позже. Пока нам
достаточно знать, что они каким-то образом сохраняют содер-
жимое регистров в памяти LIFO. После их выполнения вы
вольны использовать регистры А, В и С по своему усмотре-
нию. Когда надобность в них отпадает, вы извлекаете числа из
стека в обратном порядке:
POP C
POP B
POP A
Помните: последним вошел — первым вышел. Изменив по-
рядок команд POP, вы скорее всего получите ошибку.
Стек особенно удобен тем, что его можно использовать в
различных фрагментах программы, не заботясь при этом о
потенциальных проблемах. Если вы, поместив в стек содер-
жимое регистров А, В и С, решили проделать ту же операцию
с регистрами D и E, используйте команды:
PUSH D
PUSH E
Для восстановления содержимого регистров необходимо вве-
сти в программу команды:
POP E
POP D
340
Глава девятнадцатая
до того как предыдущий фрагмент начнет извлекать из стека
содержимое регистров А, В и С.
Как работает стек? Для него выделяется область памяти, не
занятая другими данными. Для адресации этой области памя-
ти в микропроцессор 8080 включен специальный 16-битовый
регистр — указатель стека (Stack Pointer, SP).
Приведенные выше примеры записи и извлечения из сте-
ка содержимого регистров в случае 8080 не совсем корректны.
Команда PUSH в этом процессоре записывает в стек 16-бито-
вое значение, и такое же значение извлекается из стека коман-
дой POP. Поэтому вместо простых команд PUSH C и POP C в
этом процессоре применяются 8 команд:
Код
Команда
Код
Команда
C5
PUSH BC
C1
POP BC
D5
PUSH DE
D1
POP DE
E5
PUSH HL
E1
POP HL
F5
PUSH PSW
F1
POP PSW
Команда PUSH BC записывает в стек регистры B и C, а POP BC
соответственно извлекает их. В 8-битовом регистре PSW, как
вы помните, хранится слово состояния программы, т. е. флаж-
ки. Две команды в последней строке таблицы в действитель-
ности сохраняют в стеке содержимое не только регистра PSW,
но и аккумулятора. Чтобы сохранить в стеке все регистры и
флажки, используйте команды:
PUSH PSW
PUSH BC
PUSH DE
PUSH HL
а для восстановления этой информации:
POP HL
POP DE
POP BC
POP PSW
Чтобы разобраться в работе стека, допустим, что в какой-
то момент времени содержимое указателя стека равно 8000h.
341
Два классических микропроцессора
Выполнение команды PUSH BC в действительности состоит
из четырех шагов.
•
Указатель стека уменьшается на 1, становясь равным 7FFFh.
•
Содержимое регистра B сохраняется в ячейку с адресом из
указателя стека, т. е. 7FFFh.
•
Указатель стека уменьшается еще на 1, становясь равным
7FFEh.
•
Содержимое регистра C сохраняется в ячейку с адресом из
указателя стека, т. е. 7FFEh.
Команда POP BC прокручивает все эти действия в обрат-
ном порядке (при условии, что в указателе стека все еще запи-
сан адрес 7FFEh).
•
В регистр C загружается число из ячейки, адрес которой
(7FFEh) записан в указателе стека.
•
Указатель стека увеличивается на 1, становясь равным
7FFFh.
•
В регистр B загружается число из ячейки, адрес которой
(7FFFh) записан в указателе стека.
•
Указатель стека увеличивается на 1, становясь равным
8000h.
Каждая команда PUSH увеличивает размер стека на 2 бай-
та. В принципе не исключена ситуация, при которой стек (ве-
роятно, из-за ошибки в программе) так вырастет, что начнет
записываться поверх кодов команд и данных, нужных для вы-
полнения программы. Это называется переполнением стека
(stack overflow). Подобным же образом ошибочное использо-
вание лишних команд POP приводит к исчезновению стека
(stack underflow).
Если вы подключили к процессору 8080 память емкостью
64 кб, начальное значение указателя стека удобно сделать рав-
ным 0000h. Первая команда PUSH приведет к его уменьше-
нию на 1, т. е. запись стека начнется с адреса FFFFh, и он зай-
мет область памяти, максимально далекую от ваших программ,
которые, вероятно, будут располагаться, начиная с адреса
0000h.
Задать значение указателя стека позволяет команда LXI
(Load Extended Immediate, расширенная непосредственная заг-
342
Глава девятнадцатая
рузка), предназначенная для записи в 16-битовую пару регис-
тров двух байтов, следующих за кодом команды.
Код
Команда
01
LXI BC,xxxx
11
LXI DE,xxxx
21
LXI HL,xxxx
31
LXI SP,xxxx
Команда:
LXI BC,527Ah
эквивалентна командам:
MVI B,52h
MVI C,7Ah
но занимает в памяти на целый байт меньше. Последняя
команда в таблице служит для записи определенного числа в
регистр SP, т. е. в указатель стека. Как правило, она оказывает-
ся одной из первых команд, выполняемых процессором после
перезапуска:
0000h: LXI SP,0000h
Для увеличения или уменьшения на 1 содержимого пар
регистров и указателя стека служат специальные команды:
Код
Команда
Код
Команда
03
INX BC
0B
DCX BC
13
INX DE
1B
DCX DE
23
INX HL
2B
DCX HL
33
INX SP
3B
DCX SP
Раз уж я заговорил о 16-битовых командах, упомяну еще
несколько. Следующие команды складывают содержимое 16-
битовой пары регистров с парой HL.
Код
Команда
09
DAD HL,BC
19
DAD HL,DE
343
Два классических микропроцессора
29
DAD HL,HL
39
DAD HL,SP
Их использование также сокращает размер программы. На-
пример, чтобы заменить DAD HL,BC, вам понадобилось бы
шесть обычных команд:
MOV A,L
ADD A,C
MOV L,A
MOV A,H
ADC A,B
MOV H,A
Обычно команду DAD применяют для вычисления адресов в
памяти. Из всех флажков она влияет лишь на флажок переноса.
Нам осталось рассмотреть еще несколько команд. SHLD и
LHLD служат для сохранения в памяти содержимого пары ре-
гистров HL и для записи информации из памяти в эту пару
регистров.
Код
Команда
Действие
22
SHLD [aaaa],HL
Сохранить содержимое HL
2A
LHLD HL,[aaaa]
Загрузить данные в HL
Число из регистра L записывается по адресу [aaaa], а число из
регистра H — по адресу [aaaa + 1].
В программный счетчик (Program Counter, PC) и указатель
стека можно записать число из пары регистров HL:
Код
Команда
Действие
E9
PCHL PC,HL
Записать число из HL в PC
F9
SPHL SP,HL
Записать число из HL в SP
PCHL в действительно является разновидностью команды пере-
хода, так как следом за ней будет выполнена команда, адрес кото-
рой записан в паре регистров HL. Команда SPHL предоставляет
альтернативный способ задать значение указателя стека.
Две следующие команды позволяют поменять местами со-
держимое пары регистров HL либо с «верхним» элементом
стека, либо с парой регистров DE.
(продолжение)
344
Глава девятнадцатая
Код
Команда
Действие
E3
XTHL HL,[SP]
Поменять местами HL и
«верхний» элемент стека
EB
XCNG HL,DE
Поменять местами HL и DE
Теперь о командах ветвления. Как вы помните из главы 17,
в процессоре имеется специальный регистр — программный
счетчик, — куда записан адрес следующей команды, которую
должен выполнить процессор. Обычно команды выполняют-
ся последовательно, согласно их расположению в памяти. Но
некоторые — а именно команды перехода — позволяют про-
цессору отклониться от этого генерального курса. Их выпол-
нение приводит к записи в программный счетчик значения,
выпадающего из общей последовательности.
Хотя отказываться от старого доброго безусловного перехо-
да никто вас не призывает, куда удобнее оказываются команды
условного перехода, действие которых зависит от состояния
определенных флажков, например, флажка переноса или
флажка нуля. Именно способность осуществлять условный
переход превратила автоматический сумматор из главы 17 в
настоящий многоцелевой компьютер.
У процессора 8080 пять флажков, четыре из которых ис-
пользуются в командах условного перехода. Всего в наборе 8080
предусмотрено 9 команд перехода: одна для безусловного пе-
рехода и еще 8 для перехода в зависимости от равенства 0 или
1 флажков нуля, переноса, четности и знака.
Прежде чем познакомить вас с ними, я хотел бы ввести еще
два типа переходов. Первый из них осуществляет команда
CALL (вызов). Она приводит в общем-то к обычному услов-
ному переходу с одним исключением: прежде чем записать в
программный счетчик новое значение, процессор сохраняет
адрес, который был в нем до этого. Где? Конечно, в стеке!
Это означает, что в процессоре сохраняется информация,
откуда был совершен переход. Сохраненный адрес позволяет
процессору вернуться к выполнению прерванной последова-
тельности команд. Для этого обратного перехода служит ко-
манда RET (Return, вернуться). Она извлекает 2 байта из стека
и помещает их в программный счетчик.
Наличие команд, подобных CALL и RET, в арсенале любо-
го процессора очень важно, так как они позволяют создавать
345
Два классических микропроцессора
подпрограммы, т. е. выделять часто используемые фрагменты
кода («часто» в данном случае означает «больше одного раза»).
Подпрограммы являются главным организующим элементом
программы на языке ассемблера.
Рассмотрим пример. Разрабатывая программу на языке ас-
семблера, вы столкнулись с необходимостью перемножить два
байта. Естественно, вы вставляете в код фрагмент, который
решает эту задачу, и продолжаете работать. Вскоре потребность
в умножении возникает опять. Конечно, можно использовать
те же команды, что и раньше. Но нужно ли второй раз встав-
лять их в программу? Думаю, нет. Это же напрасная трата па-
мяти! Разумно было бы использовать для умножения уже вве-
денные команды, но как к ним перейти? Обычная команда бе-
зусловного перехода здесь не подойдет, так как она не позво-
ляет после умножения вернуться обратно. Вот здесь-то в дей-
ствие и вступают команды CALL и RET.
Набор команд, осуществляющих умножение двух байтов,
— прекрасный пример подпрограммы. Рассмотрим ее подроб-
нее. В главе 17 перемножаемые байты и произведение храни-
лись в ячейках памяти. В подпрограмме для процессора 8080
мы разместим множители в регистрах В и С, а произведение
запишем в пару регистров HL.
Multiply: PUSH PSW
; Сохраняем регистры, которые
PUSH BC
; будут меняться
SUB H,H
; Записываем 0000h в HL (результат)
SUB L,L
MOV A,B
; Записываем множитель в А
CPI A,00h
; Если он 0, завершаем
JZ AllDone
MVI B,00h
; Записываем 0 в старший байт BC
MultLoop: DAD HL,BC
; Складываем HL и BC
DEC A
; Уменьшаем множитель на 1
JNZ MultLoop
; Возврат на начало цикла, если
; не 0
346
Глава девятнадцатая
AllDone: POP BC ; Восстанавливаем регистры
POP PSW
RET
; Возврат
Первая строчка подпрограммы начинается с метки Multiply,
соответствующей адресу в памяти, по которому расположена
подпрограмма. Начинается выполнение подпрограммы с двух
команд PUSH. Обычно регистры, используемые в подпрограм-
ме, желательно сохранять, а после окончания ее работы — вос-
станавливать.
Затем подпрограмма обнуляет содержимое регистров H и L.
То же действие можно выполнить и с помощью команд MVI,
но их понадобилось бы 4, а не 2, как команд SUB. По заверше-
нии работы подпрограммы пара регистров HL будет содержать
искомое произведение.
Следующий шаг: перемещение содержимого регистра В в
аккумулятор и проверка его равенства 0. Если множитель ра-
вен 0, произведение также равно 0, и работу подпрограммы
можно считать законченной. В регистры H и L ноль уже запи-
сан, так что можно с помощью команды JZ (переход, если 0)
переходить прямо к двум завершающим командам POP.
Если множитель 0 не равен, программа обнуляет регистр
В. Теперь один из множителей содержится в аккумуляторе,
второй — в паре регистров ВС. Команда DAD складывает мно-
житель (ВС) с результатом (HL). Значение множителя в акку-
муляторе уменьшается на 1. Если результат не равен 0, коман-
да JNZ (переход, если не 0) приводит к повторному сложению
ВС и HL. Выполнение этого короткого цикла продолжается,
пока содержимое аккумулятора не обратится в 0 (отмечу, что
более эффективную программу умножения для процессора
8080 можно написать с помощью команд сдвига).
Если в основной программе возникла необходимость ум-
ножить 25h на 12h, это делают команды:
MVI B,25h
MVI C,12h
CALL Multiply
Команда CALL записывает в стек содержимое программного
счетчика, т. е. адрес команды, стоящей следом за командой
CALL. Затем происходит переход к команде, на которую ука-
347
Два классических микропроцессора
зывает метка Multiply, т. е. к началу подпрограммы. Когда про-
изведение в подпрограмме вычислено, выполняется команда
RET, в результате чего в программный счетчик возвращается
значение из стека. Далее выполняется команда, идущая за
CALL.
В набор команд процессора 8080 входят также условные
команды вызова подпрограммы и возвращения из нее, но ис-
пользуются они гораздо реже обычных команд условного пе-
рехода:
Условие
Код Команда Код
Команда
Код
Команда
Нет
C9
RET
C3
JMP aaaa
CD
CALL aaaa
Не ноль
C0
RNZ
C2
JNZ aaaa
C4
CNZ aaaa
Ноль
C8
RZ
CA
JZ aaaa
CC
CZ aaaa
Нет
D0
RNC
D2
JNC aaaa
D4
CNC aaaa
переноса
Есть
D8
RC
DA
JC aaaa
DC
CC aaaa
перенос
Результат
E0
RPO
E2
JPO aaaa
E4
CPO aaaa
нечетный
Результат
E8
RPE
EA
JPE aaaa
EC
CPE aaaa
четный
Результат
F0
RP
F2
JP aaaa
F4
CP aaaa
положителен
Результат
F8
RM
FA
JM aaaa
FC
CM aaaa
отрицателен
Вы, вероятно, и без меня знаете, что к процессору подклю-
чают не только память. Компьютер — ничто без устройств
ввода и вывода, позволяющих ему обмениваться информаци-
ей с окружающим миром. Самые популярные устройства ввода
и вывода — клавиатура и дисплей.
Как процессор обменивается информацией с периферий-
ными (peripheral) устройствами, т. е. со всеми подключенны-
ми к нему устройствами, кроме памяти? Обычно внешние
устройства конструируют так, что с точки зрения подключе-
ния к процессору они ведут себя подобно памяти. Микропро-
цессор считывает информацию из устройства и записывает ее,
задавая адрес, который соответствует этому устройству. В не-
348
Глава девятнадцатая
которых микропроцессорах адреса внешним устройствам вы-
деляются из обычного адресного пространства. Такая органи-
зация называется вводом-выводом с распределением памяти
(memory-mapped input/output). В процессоре 8080 для уст-
ройств ввода-вывода 256 адресов зарезервированы в дополне-
ние к основной памяти с 65 536 адресами. Эти дополнитель-
ные адреса называются портами ввода-вывода (input/output
ports). Адреса портов подаются на адресные линии с A
0
по A
7
.
От адресов памяти их с помощью системного контроллера 8228
отличают специальные управляющие сигналы.
Запись содержимого аккумулятора в порт осуществляет
команда OUT. Адрес порта указывается вслед за ее кодом. Для
считывания байта в аккумулятор предназначена команда IN.
Код
Команда
D3
OUT pp
DB
IN pp
В некоторых случаях периферийным устройствам надо
«привлечь внимание» процессора. Например, когда вы нажи-
маете клавишу на клавиатуре, процессору, как правило, жела-
тельно знать об этом сразу. Осуществляет это механизм пре-
рываний (interrupts) — сигналов, поступающих в процессор
8080 через вход INT.
После перезапуска процессор 8080 на прерывания не реа-
гирует. Чтобы разрешить прерывания, в программу нужно
вставить команду EI (Enable Interrupts, разрешить прерывания),
а чтобы отказаться от реагирования на них — DI (Disable
Interrupts, запретить прерывания).
Код
Команда
F3
DI
FB
EI
Когда прерывания разрешены, подается сигнал на выход
процессора INTE. Когда устройству нужно прервать работу
процессора, оно подает сигнал на вход INT. Процессор извле-
кает из памяти очередную команду программы, но выполняет
не ее, а одну из следующих:
349
Два классических микропроцессора
Код
Команда
Код
Команда
C7
RST 0
E7
RST 4
CF
RST 1
EF
RST 5
D7
RST 2
F7
RST 6
DF
RST 3
FF
RST 7
Действуют они подобно команде CALL в том смысле, что
при их выполнении в стек записывается содержимое про-
граммного счетчика. Но переход при этом осуществляется по
строго определенным адресам: команда RST 0 передает управ-
ление команде по адресу 0000h, RST 1 — команде по адресу
0008h и т. д. до RST 7, которая передает управление команде по
адресу 0038h. По этим адресам должны располагаться фраг-
менты кода, реагирующие на прерывания. Допустим, что пре-
рывание от клавиатуры привело к срабатыванию RST 4. Зна-
чит, по адресу 0020h должны располагаться команды для счи-
тывания с клавиатуры введенного байта (подробнее об этом в
главе 21).
Я описал 243 команды. Неиспользованными остались
коды 08h, 10h, 18h, 20h, 28h, 30h, 38h, CBh, D9h, DDh, EDh и
FDh. В заключение упомяну еще один код и соответствую-
щую команду.
Код
Команда
00
NOP
NOP (No Operation, нет операции) не выполняет никаких дей-
ствий. Зачем она нужна? Например, для заполнения пустых
ячеек.
Обсуждать с теми же подробностями процессор 6800 фир-
мы Motorola я не собираюсь, поскольку он как по конструк-
ции, так и по действию довольно похож на процессор 8080.
Вот какие у него есть выводы.
350
Глава девятнадцатая
V
SS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
40
39
38
37
36
35
34
33
32
31
30
29
28
27
26
25
24
23
22
21
A
12
A
13
A
14
A
15
D
7
D
6
D
5
D
4
D
3
D
2
D
1
D
0
R/W
DBE
0
2
TSC
RESET
A
11
A
10
A
9
A
8
A
7
A
6
A
5
A
4
A
3
A
2
A
1
A
0
V
CC
BA
NMI
VMA
IRQ
0
1
HALT
V
SS
MC6800
Контакт V
SS
соединяется с землей, контакт V
CC
— с питанием
5 В. Подобно микросхеме 8080, у процессора 6800 имеется 16
адресных входов и 8 сигналов для данных, применяемых как
для ввода, так и для вывода информации. На вход IRQ подает-
ся запрос на прерывание (interrupt request). Порты ввода-выво-
да в 6800 не используются. Адреса устройств берутся из обыч-
ного адресного пространства.
Есть в процессоре 6800 16-битовый программный счетчик,
16-битовый указатель стека, 8-битовый регистр состояния (для
флажков) и два 8-битовых аккумулятора А и В. В считается
именно аккумулятором, а не регистром, поскольку с ним мож-
но выполнять все те же операции, что и с А. Других 8-битовых
регистров в процессоре нет.
16-битовые значения в 6800 хранятся в индексном регистре
(index register), подобном паре регистров HL в 8080. Адрес для
многих команд вычисляется суммированием содержимого ин-
дексного регистра и байта, следующего за кодом команды.
351
Два классических микропроцессора
Хотя набор команд процессора 6800 в целом идентичен
набору процессора 8080, очевидно, что численные и мнемо-
нические коды этих команд совершенно различны. Вот, напри-
мер, как выглядят в наборе 6800 команды перехода.
Код
Команда
Действие
20
BRA
Переход
22
BHI
Переход, если больше
23
BLS
Переход, если меньше или равно
24
BCC
Переход, если нет переноса
25
BCS
Переход, если есть перенос
26
BNE
Переход, если не равно
27
BEQ
Переход, если равно
28
BVC
Переход, если нет переполнение
29
BVS
Переход, если есть переполнение
2A
BPL
Переход, если плюс
2B
BMI
Переход, если минус
2C
BGE
Переход, если больше или равно 0
2D
BLT
Переход, если меньше 0
2E
BGT
Переход, если больше 0
2F
BLE
Переход, если меньше или равно 0
Флажка четности в 6800 нет, зато в отличие от 8080 есть фла-
жок переполнения. Действие некоторых команд перехода за-
висит от сочетания флажков.
Различие наборов команд 8080 и 6800 удивления, разуме-
ется, не вызывает. Две этих микросхемы разрабатывались
практически одновременно двумя группами инженеров двух
различных компаний. Поэтому они и несовместимы: машин-
ные коды одного процессора не работают на другом процес-
соре. Даже программу на языке ассемблера, написанную для
одного процессора, нельзя перевести в машинные коды дру-
гого процессора. О программах, которые работают на разных
процессорах, мы поговорим в главе 24.
352
Глава девятнадцатая
Между процессорами 8080 и 6800 есть и другое интересное
отличие. В обоих наборах есть команда LDA, загружающая в
аккумулятор содержимое ячейки памяти. В 8080, например,
следующая последовательность байтов:
3Ah
7Bh
34h
Команда LDA процессора 8080
приведет к записи в аккумулятор байта из ячейки с адресом
347Bh. Теперь сравните это с командой LDA из набора процес-
сора 6800 в так называемом расширенном режиме адресации:
B6h
7Bh
34h
Команда LDA процессора 6800
Эта последовательность байтов приведет к записи в аккуму-
лятор байта из ячейки с адресом 7B34h.
В различии кодов команд (3Ah в 8080 и B6h в 6800) нет, как
мы уже говорили, ничего удивительного. Но процессоры так-
же по-разному обрабатывают байты, которые следуют за ко-
дом команды. В программе для процессора 8080 считается, что
сначала за кодом идет младший байт адреса, а потом — стар-
ший. В программе же для процессора 6800 сначала идет стар-
ший байт!
Это фундаментальное различие в способе хранения мно-
гобайтовых величин между процессорами фирм Intel и
Motorola так и не устранено. И в наши дни в процессорах
фирмы Intel многобайтовые величины хранятся, начиная с
младшего байта, а в процессорах фирмы Motorola — начиная
со старшего.
Помните из-за чего Лилипутия воевала с государством Бле-
фуску? Из-за разногласий по поводу того, с какого конца над-
лежит разбивать вареные яйца: с острого или тупого. Споры
между сторонниками двух способов записи многобайтовых
353
Два классических микропроцессора
величин сродни спорам между остроконечниками и тупоко-
нечниками (так Джонатан Свифт назвал приверженцев враж-
дующих партий) и настолько же лишены смысла (хотя дол-
жен признаться, что мне самому способ, использованный в
компьютере из главы 17, не очень нравится!). Сами по себе оба
метода «правильны», но различие между ними создает боль-
шие трудности при необходимости переносить информацию
с компьютеров остроконечников (Intel) на компьютеры тупо-
конечников (Motorola).
Какая судьба ожидала процессоры 8080 и 6800? Первый стал
основой устройства, которое иногда называют первым персо-
нальным компьютером, хотя правильнее было бы называть его
первым домашним компьютером. Это устройство — компью-
тер «Альтаир 8800», в январе 1975 г. украсивший обложку жур-
нала «Popular Electronics».
Взгляните на него: лампочки, переключатели — все это нам
знакомо, правда? Именно так выглядел пульт управления па-
мятью, который я описал вам в главе 16.
За процессором 8080 последовали чипы 8085 и Z-80 фир-
мы Zilog — конкурента корпорации Intel, основанного быв-
354
Глава девятнадцатая
шим работником последней Федерико Фаггином (Federico
Faggin), который принимал активное участие в работе над мик-
росхемой 4004. Процессор Z-80 был полностью совместим с
8080, но отличался от него наличием множества очень полез-
ных дополнительных команд.
В 1977 г. появился компьютер «Apple II» компании Apple
Computer, основанной Стивеном Джобсом (Steven Jobs) и Сте-
фаном Возняком (Stephen Wozniak). В нем был применен усо-
вершенствованный вариант 6800 — дешевый микрочип 6502
фирмы MOS Technology.
В июне 1978 г. фирма Intel выпустила 16-битовый процес-
сор 8086 с адресным пространством 1 Мб. Его машинные коды
были несовместимы с кодами 8080, зато включали специаль-
ные команды для умножения и деления. Годом позже появил-
ся процессор 8088, внутренне идентичный 8086, но адресовав-
ший память побайтово. Это позволяло использовать в сочета-
нии с ним широко распространенные вспомогательные мик-
росхемы, разработанные для процессора 8080. На процессоре
8088 работал персональный компьютер 5150 фирмы IBM (бо-
лее известный как IBM PC), появившийся осенью 1981 г.
IBM оказала на рынок персональных компьютеров громад-
ное влияние. Многие компании занялись выпуском компью-
теров, совместимых с IBM PC (смысл понятия «совместимость»
я разъясню в следующих главах). В 1982 г. семейство процес-
соров x86 пополнилось чипами 186 и 286, в 1985 г. появился
32-разрядный процессор 386, в 1986 г. — 486. С 1993 г. в IBM-
совместимых компьютерах используются процессоры Pentium
фирмы Intel. Хотя наборы команд этих процессоров постоян-
но расширяются, в них неизменно поддерживаются и коман-
ды всех предыдущих версий, начиная с 8086.
Прямым наследником процессора 6800 стал 16-разрядный
чип 68000 фирмы Motorola, ставший в 1984 г. основой компь-
ютера «Apple Macintosh». Этот процессор и последовавшие за
ним процессоры той же серии (иногда ее называют 68К) и по
сей день имеют многочисленных поклонников.
С 1996 г. в компьютерах «Macintosh» используется микро-
процессор PowerPC, разработанный совместно компаниями
Motorola, IBM и Apple. Он построен с использованием архи-
тектуры RISC (Reduced Instruction Set Computing, вычисления
355
Два классических микропроцессора
с сокращенным набором команд), в которой предпринята по-
пытка повысить быстродействие процессора за счет его упро-
щения в некоторых отношениях. В RISC-компьютере все ко-
манды, как правило, имеют одну и ту же длину (в PowerPC она
равна 32 битам), доступ к памяти органичен командами заг-
рузки и сохранения, и вообще команды выполняют максималь-
но простые действия. Обычно RISC-компьютеры снабжены
большим числом регистров, чтобы избежать частых обраще-
ний к памяти.
Набор команд PowerPC кардинально отличается от набора
серии 68К, поэтому запустить на PowerPC программу для про-
цессора 68К нельзя. Однако в процессорах PowerPC, устанав-
ливаемых на компьютерах «Apple Macintosh», предусмотрена
возможность эмуляции процессора 68К. Программа-эмулятор
по одному просматривает все машинные коды программы для
68К и выполняет соответствующее действие. Это, конечно, не
так быстро, как программа, изначально написанная для
PowerPC, но работает.
Согласно закону Мура количество транзисторов в микро-
процессорах удваивается каждые полтора года. Для чего ис-
пользуются все эти дополнительные транзисторы?
Некоторые из них позволили повысить разрядность процес-
сора, другие — расширить набор его команд. В большинстве
современных микропроцессоров имеются специальные коман-
ды для арифметических операций с вещественными числами
(подробнее в главе 23). Специальные команды разработаны для
выполнения многократных вычислений, потребность в кото-
рых возникает при отображении на экране компьютера графи-
ческих изображений (в том числе движущихся).
В современных процессорах используется несколько мето-
дов повышения быстродействия, в частности, конвейеризация
(pipelining). Выполняя одну инструкцию, процессор заранее
считывает следующую, пытаясь предсказать возможное ветв-
ление программы. Еще одно нововведение — кэш (cache),
сверхбыстрая память внутри процессора, в которой хранятся
недавно выполнявшиеся команды. Когда в программе встре-
чается короткий цикл, кэш позволяет ускорить его выполне-
ние за счет того, что команды не нужно многократно считы-
вать из памяти. Для всех этих усовершенствований необходи-
мы новые логические схемы, а значит, новые транзисторы.
356
Глава девятнадцатая
Я уже говорил, что процессор — лишь часть завершенной
компьютерной системы (хотя и самая важная). Такую систему
мы спроектируем в главе 21, а пока обратимся к тому, как хра-
нить в памяти нечто, отличное от кодов команд и чисел. Итак,
возвращаемся в первый класс и учимся читать и писать.
|