кр гаряев. Чарльз Петцольд - Код_ тайный язык информатики-Манн, Иванов и Фе. Книга принадлежит Контакты владельца Культовая книга талантливого преподавателя стала для многих первым уверенным шагом в программировании
Скачать 6.11 Mb.
|
Код Команда 32 STA [aaaa], A 3A LDA A,[aaaa] В дополнение к аккумулятору процессор 8080 имеет шесть регистров, которые также могут содержать 8-битные значения. Эти регистры похожи на аккумулятор. На самом деле аккумулятор считается регистром особого типа. Подобно аккумулятору, остальные шесть регистров являются защелка- ми; процессор может перемещать байты из памяти в регистры и из регистров обратно в память. В отличие от аккумулятора, регистры не так функциональ- ны. Например, при сложении двух 8-битных чисел результат всегда попадает в аккумулятор, а не в один из регистров. Шесть дополнительных регистров в процессоре 8080 называются B, C, D, E, H и L. Первым делом люди спрашивают: «Что же случилось с F и G?» — а затем задают второй вопрос: «А как насчет I, J и K?» Ответ заключается в том, что регистры H и L обладают некоторыми особенностями, а их название происходит от слов high и low. Часто 8-битные значения в регистрах H и L обрабатываются вместе в виде 16-битной пары регистров HL, при этом в регистре H содержится старший (high) байт, а в регистре L — младший (low). Это 16-битное значение используется для адресации памяти. Чуть позже мы увидим, как это работает. Так ли необходимы все эти регистры? Почему мы в них не нуждались, соби- рая компьютер в главе 17? Теоретически использовать их не обязательно, а прак- тически — весьма удобно. Многие компьютерные программы способны одновре- менно манипулировать несколькими числами. Это проще всего делать, если числа хранятся не в памяти, а в регистрах микропроцессора. Кроме того, программа работает быстрее: чем реже она обращается к памяти, тем быстрее выполняется. Для команды процессора 8080 под названием MOV (Move — переместить) предусмотрено 63 кода. Эти коды занимают только один байт и, как правило, перемещают содержимое одного регистра в другой или в тот же самый. Мно- жество команд MOV — следствие использования в микропроцессоре семи ре- гистров (включая аккумулятор). 300 Код Вот первые 32 команды MOV. Помните, что место назначения соответ- ствует аргументу слева, а источник — аргументу справа. Код Команда Код Команда 40 MOV B, B 50 MOV D, B 41 MOV B, C 51 MOV D, C 42 MOV B, D 52 MOV D, D 43 MOV B, E 53 MOV D, E 44 MOV B, H 54 MOV D, H 45 MOV B, L 55 MOV D, L 46 MOV B,[HL] 56 MOV D,[HL] 47 MOV B, A 57 MOV D, A 48 MOV C, B 58 MOV E, B 49 MOV C, C 59 MOV E, C 4A MOV C, D 5A MOV E, D 4B MOV C, E 5B MOV E, E 4C MOV C, H 5C MOV E, H 4D MOV C, L 5D MOV E, L 4E MOV C,[HL] 5E MOV E,[HL] 4F MOV C, A 5F MOV E, A Как видите, весьма удобные команды. При наличии значения в одном из регистров можно переместить его в другой. Обратите внимание на четыре команды, которые используют пару регистров HL, например на следующую. MOV B,[HL] Упомянутая выше команда LDA перемещает байт из памяти в аккумуля- тор; 16-битный адрес этого байта следует непосредственно за кодом команды LDA. Эта команда MOV перемещает байт из памяти в регистр B. Однако адрес байта, который должен быть загружен в регистр, хранится в паре регистров HL. Как 16-битный адрес оказался в паре регистров HL? Это могло произойти разными способами. Возможно, этот адрес был каким-то образом вычислен. В общем, обе команды загружают байт из памяти в микропроцессор, но ис- пользуют два разных метода для адресации памяти. Первый метод называется прямой адресацией, а второй — индексной адресацией. LDA A,[aaaa] MOV B,[HL] Глава 19. Два классических микропроцессора 301 Второй набор из 32 команд MOV показывает, что ячейки памяти, адре- суемые парой регистров HL, могут являться не только источником, но и мес- том назначения. Код Команда Код Команда 40 MOV B, B 50 MOV D, B 60 MOV H, B 70 MOV [HL], B 61 MOV H, C 71 MOV [HL], C 62 MOV H, D 72 MOV [HL], D 63 MOV H, E 73 MOV [HL], E 64 MOV H, H 74 MOV [HL], H 65 MOV H, L 75 MOV [HL], L 66 MOV H,[HL] 76 HLT 67 MOV H, A 77 MOV [HL], A 68 MOV L, B 78 MOV A, B 69 MOV L, C 79 MOV A, C 6A MOV L, D 7A MOV A, D 6B MOV L, E 7B MOV A, E 6C MOV L, H 7C MOV A, H 6D MOV L, L 7D MOV A, L 6E MOV L,[HL] 7E MOV A,[HL] 6F MOV L, A 7F MOV A, A Некоторые из этих команд, например MOV A, A, не делают ничего полез- ного. Команды MOV [HL],[HL] вообще не существует. Код, который мог бы ей соответствовать, выделен команде HLT (Halt — остановить). Более показательный способ анализа команд MOV — рассмотрение бито- вого шаблона их кода. Код команды MOV состоит из восьми битов: 01ннниии, где буквы ннн соответствуют 3-битному коду места назначения, а иии — 3-бит- ному коду источника. Эти 3-битные коды обозначают следующие регистры. 000 = регистр B 001 = регистр C 010 = регистр D 011 = регистр E 100 = регистр H 101 = регистр L 302 Код 110 = ячейка памяти по адресу HL 111 = аккумулятор Команда MOV L, E соответствует коду 01101011, или 6Bh. Вы можете све- риться с предыдущей таблицей, чтобы убедиться в этом. Вероятно, где-то внутри процессора 8080 три бита иии используются в се- лекторе «8 на 1», а три бита ннн управляют дешифратором «3 на 8», опреде- ляющим регистр, где будет зафиксировано значение. Регистры B и C также можно использовать как 16-битную пару регистров BC, а регистры D и E — как 16-битную пару регистров DE. Если в любой из этих пар регистров содержится адрес ячейки памяти, откуда вы хотите считать или куда хотите записать байт, можете использовать следующие команды. Код Команда Код Команда 02 STAX [BC], A 0A LDAX A,[BC] 12 STAX [DE], A 1A LDAX A,[DE] Другой тип команды Move называется Move Immediate («Перемес тить не- посредственно») и обозначается мнемокодом MVI. Эта команда состоит из двух байтов. Первый — код команды, второй — байт данных. Этот байт перемеща- ется из памяти в один из регистров или в ячейку памяти, адрес которой со- держится в паре регистров HL. Код Команда 06 MVI B, xx 0 E MVI C, xx 16 MVI D, xx 1E MVI E, xx 26 MVI H, xx 2E MVI L, xx 36 MVI [HL], xx 3E MVI A, xx Например, после выполнения команды MVI E,37h в регистре E будет со- держаться байт 37h. Этот третий метод обращения к памяти называется не- посредственной адресацией. Набор из 32 кодов команд выполняет четыре основные арифметичес- кие операции, с которыми мы познакомились, когда собирали процессор (глава 17). К ним относятся сложение (ADD), сложение с переносом (ADC), Глава 19. Два классических микропроцессора 303 вычитание (SUB) и вычитание с заимствованием (SBB). Во всех случаях ак- кумулятор является одним из двух операндов, а также местом назначения для результата. Код Команда Код Команда 8 0 ADD A, B 9 0 SUB A, B 81 ADD A, C 91 SUB A, C 82 ADD A, D 92 SUB A, D 83 ADD A, E 93 SUB A, E 84 ADD A, H 94 SUB A, H 85 ADD A, L 95 SUB A, L 86 ADD A,[HL] 96 SUB A,[HL] 87 ADD A, A 97 SUB A, A 88 ADC A, B 98 SBB A, B 89 ADC A, C 99 SBB A, C 8A ADC A, D 9A SBB A, D 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. Если в A содержится байт 35h, в регистре H — 10h, в регистре L — 7Ch, в ячейке памяти 107Ch — 4Ah, то при выполнении команды ADD A,[HL] байт в аккумуляторе (35h) прибавляется к байту в ячейке, к которой обращается пара регистров HL (4Ah), а результат (7Fh) сохраняется в аккумуляторе. Команды ADC и SBB позволяют процессору 8080 складывать и вычитать 16-, 24-, 32-битные числа, а также числа большей разрядности. Предположим, что пары регистров BC и DE содержат 16-битные числа. Вы хотите сложить их и поместить результат в пару регистров BC. Это можно сделать так. MOV A, C ; младший байт ADD A, E MOV C, A MOV A, B ; старший байт ADC A, D MOV B, A 304 Код Для сложения используются две команды: ADD — для младшего байта, ADC — для старшего. Любой бит переноса, возникающий в результате первого сложения, участвует во втором сложении. Поскольку прибавлять можно только к значению в аккумуляторе, в этом небольшом фрагменте кода команда MOV используется не менее четырех раз. Команды MOV очень часто встречаются в программном коде для процессора 8080. Пришло время поговорить о флагах микросхемы 8080. В процессоре из гла- вы 17 использовались флаг переноса и флаг нуля. Микросхема 8080 предусмат- ривает еще три флага: знака, четности и вспомогательного переноса. Все флаги хранятся в 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 (Decimal Adjust Accumulator — десятичная коррекция аккумулятора). На флаг переноса непосредственно влияют две команды. Код Команда Значение 37 STC Установить флаг переноса в 1 3F CMC Дополнить флаг переноса до 1 или инвертировать флаг переноса Глава 19. Два классических микропроцессора 305 В отличие от компьютера из главы 17, который тоже выполнял команды ADD, ADC, SUB и SBB (хотя и не с такой же степенью гибкости), процессор 8080 способен еще и на булевы операции И, ИЛИ и исключающее ИЛИ. За вы- полнение арифметических и логических операций отвечает арифметико-логи- ческое устройство процессора. Код Команда Код Команда 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 выполняются побитово, то есть отдельно над каждой парой битов. Например, в результате выполнения следующих команд значение в аккумуляторе будет равно 05h. MVI A,0Fh MVI B,55h AND A, B Если бы последней была команда OR, то результат был бы равен 5Fh; если бы последней была команда XOR — 5Ah. Команда CMP (Compare — сравнить) аналогична команде SUB, за исклю- чением того, что результат не сохраняется в аккумуляторе. Другими слова- ми, команда CMP выполняет вычитание, а затем удаляет результат. В чем же смысл? Во флагах! Флаги говорят о том, как два сравниваемых байта соотно- сятся. Рассмотрим, например, следующие команды. 306 Код MVI B,25h CMP A , B После их выполнения содержимое аккумулятора (А) остается прежним. Если значение в A равно 25h, будет установлен флаг нуля, а если значение в A меньше 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 Вот еще две команды для процессора 8080. Код Команда 27 DAA 2F CMA Команда CMA (Complement Accumulator — дополнить аккумулятор) вы- полняет дополнение значения в аккумуляторе до 1. Каждый 0 обращается в 1, а 1 — в 0. Если в аккумуляторе содержится значение 01100101, то после ис- полнения команды CMA в нем будет содержаться значение 10011010. Этого же результата можно достичь и с помощью следующей команды. XRI A, FFh Упомянутая выше команда DAA (Decimal Adjust Accumulator — десятич- ная коррекция аккумулятора), вероятно, является самой сложной в наборе ко- манд процессора 8080. Специально для нее в микропроцессоре предусмотрено небольшое устройство. DAA помогает программисту выполнять арифметические операции над десятичными числами в кодировке BCD (binary-coded decimal — десятичное в двоичной кодировке), где каждая тетрада может принимать значение только Глава 19. Два классических микропроцессора 307 в диапазоне от 0000 до 1001, то есть от 0 до 9 в десятичном выражении. В фор- мате BCD в восьми битах байта могут храниться две десятичные цифры. Предположим, что в аккумуляторе содержится BCD-значение 27h, кото- рое фактически соответствует десятичному значению 27, а в регистре B со- держится BCD-значение 94h. (Обычно шестнадцатеричное значение 27h эк- вивалентно десятичному значению 39.) В результате выполнения следующих команд в аккумуляторе будет содержаться значение BBh, которое, разумеется, не является BCD-значением, поскольку в кодировке BCD-значение тетрады не может превышать 9. MVI A,27h MVI B,94h ADD A, B Однако при выполнении команды DAA в аккумулятор помещается значе- ние 21h и устанавливается флаг переноса, поскольку сумма десятичных чисел 27 и 94 равна 121. Эта команда может пригодиться для арифметических опе- раций над числами в кодировке BCD. Часто возникает необходимость в прибавлении 1 к значению или в вы- читании 1 из значения. В программе для выполнения умножения, описан- ной в главе 17, нужно вычесть из значения 1, и мы делали это, прибавляя значение FFh, которое является дополнением до 2 числа –1. Процессор 8080 предусматривает специальные команды для увеличения на 1 (инкременти- рования) и уменьшения на 1 (декрементирования) значения в регистре или в ячейке памяти. Код Команда Код Команда 04 INR B 05 DCR B 0С INR C 0D DCR C 14 INR D 15 DCR D 1С INR E 1D DCR E 24 INR H 25 DCR H 2C INR L 2D DCR L 34 INR [HL] 35 DCR [HL] 3C INR A 3D DCR A Однобайтовые команды INR и DCR влияют на все флаги, кроме флага переноса. 308 Код Набор команд процессора 8080 также включает четыре команды цикли- ческого сдвига, которые сдвигают содержимое аккумулятора на один бит вле- во или вправо. Код Команда Значение 07 RLC Сдвинуть аккумулятор влево 0F RRC Сдвинуть аккумулятор вправо 17 RAL Сдвинуть аккумулятор влево через бит переноса 1F RAR Сдвинуть аккумулятор вправо через бит переноса Эти команды влияют только на флаг переноса. Предположим, что аккумулятор содержит значение A7h, или 10100111 в двоичном формате. Команда RLC сдвигает биты влево. Старший бит, вы- талкиваемый за левую границу разрядной сетки, становится младшим, а так- же определяет состояние флага переноса. В результате получается значение 01001111, а флаг переноса устанавливается в 1. Команда RRC точно так же сдвигает биты вправо. После выполнения команды RRC значение 10100111 превращается в 11010011, а флаг переноса опять устанавливается в 1. Команды RAL и RAR работают несколько иначе. При выполнении коман- ды RAL содержимое аккумулятора сдвигается влево, старший бит сохраняется во флаге переноса, а в младший бит записывается предыдущее значение фла- га переноса. Например, если аккумулятор содержит значение 10100111, а флаг переноса равен 0, то после выполнения команды RAL содержимое аккумуля- тора меняется на 01001110, а во флаг переноса записывается 1. При тех же на- чальных условиях после выполнения команды RAR значение аккумулятора аналогично меняется на 01010011, а во флаге переноса сохраняется значение 1. Команды сдвига удобны при умножении числа на 2 (сдвиг влево) и при делении числа на 2 (сдвиг вправо). Память, к которой обращается микропроцессор, называется памятью с произ- вольным доступом потому, что микропроцессор может получить дос туп к любой конкретной ячейке, просто предоставив ее адрес. Память RAM скорее напоми- нает книгу, которую можно открыть на любой странице, чем недельную под- шивку газет на микрофильме. Чтобы найти нужную информацию в субботнем выпуске, мы должны просмотреть бóльшую часть газет. Так, для воспроизведе- ния последней песни на кассете мы должны практически полностью перемотать одну из ее сторон. Микрофильм и магнитная лента относятся к запоминающим устройствам не с произвольным, а с последовательным доступом. Память с произвольным доступом, безусловно, хороша, особенно для мик- ропроцессоров, но иногда удобнее использовать запоминающее устройство, Глава 19. Два классических микропроцессора 309 доступ к которому осуществляется непроизвольно и непоследовательно. Допу- стим, вы работаете в офисе, и сотрудники подходят к вашему столу, чтобы дать задание. Выполнение каждого из них предполагает использование папки с доку- ментами. Часто при работе над одним заданием вы обнаруживаете, что не мо- жете продолжать, пока не выполните определенную задачу, используя другую папку. Так что поверх первой папки вы кладете вторую и работаете с ней. Затем вам дают еще одно задание, более приоритетное, чем предыдущее, и вы кладете новую папку поверх двух других. Для выполнения этого вам требуется еще одна папка с документами. И вот на вашем столе уже целая стопка из четырех папок. Это упорядоченный способ хранения и отслеживания всех выполняемых заданий. Самая верхняя папка всегда соответствует приоритетной задаче. Пос- ле окончания работы с этой папкой вы переходите к следующей. Когда наконец вы разберетесь с последней папкой на своем столе (с той, с которой начали), сможете отправиться домой. Технически такая форма хранения данных называется «стек». Строит- ся он снизу вверх, а разбирается сверху вниз. Элементы стека организованы по принципу «последним вошел — первым вышел» (Last In First Out, LIFO). Последний элемент, помещенный в стек, удаляется из него первым. Первый добавленный в стек элемент будет удален из него последним. Компьютеры также могут использовать стек, но не для хранения заданий, а для хранения чисел, что удобно. Добавление элемента в стек называется втал- киванием (push), а его удаление — выталкиванием (pop). Предположим, вы пишете программу на языке ассемблера, в которой ис- пользуются регистры A, B и C. На каком-то этапе программе требуется выпол- нить еще один небольшой расчет, также предполагающий применение регистров A, B и C. В итоге нужно вернуться к тому, что вы делали раньше, и продолжить использовать регистры A, B и C с теми значениями, которые в них хранились. Безусловно, вы можете просто сохранить значения регистров A, B и C в других ячейках памяти, а затем загрузить их оттуда обратно. Однако тогда нужно будет следить за содержимым ячеек памяти. Более удобный способ — помещение (вталкивание) значений регистров в стек. PUSH A PUSH B PUSH C Я объясню, как работают эти команды, чуть позже. Пока достаточно понять, что они каким-то образом сохраняют содержимое регистров в памяти LIFO. После выполнения этих команд ваша программа может спокойно использовать 310 Код эти регистры для других целей. Чтобы вернуть предыдущие значения, вы про- сто выталкиваете элементы из стека в обратном порядке. POP C POP B POP A Помните: последний помещенный в стек элемент удаляется из него в пер- вую очередь. Случайное изменение порядка команд POP приведет к ошибке. Преимущество стека в том, что его могут использовать разные разделы программы, не вызывая проблем. Например, после помещения в стек значений регистров A, B и C другому разделу программы может понадобиться сделать то же самое с регистрами C, D и E. PUSH C PUSH D PUSH E Для восстановления значения регистров используются команды РОР. POP E POP D POP C После их выполнения из стека будут извлечены значения регистров C, B и A. Как реализуется стек? Прежде всего, это просто раздел памяти, не исполь- зуемый для хранения каких-либо других данных. Для обращения к этому раз- делу памяти микропроцессор 8080 предусматривает специальный 16-битный регистр, который называется указателем стека (Stack Pointer, SP). Приведенные выше примеры добавления и удаления элементов из стека не вполне точно демонстрируют работу микропроцессора 8080. Команда 8080 PUSH фактически сохраняет в стеке 16-битные значения, а команда POP из- влекает их. Именно поэтому вместо таких команд, как PUSH C и POP C, ис- пользуем следующие восемь. |