В первой части статьи мы рассмотрели некоторые основные составляющие центрального процессора (ЦП). Настало время проникнуть дальше и посмотреть, каким образом ЦП получает команды и как выполняет их. Рассмотрим также, что такое команда в процессорном понимании.
Для того чтобы разобраться с командой, стоит обратиться к ассемблеру, как к наиболее компромиссному языку между машинным пониманием программирования и человеческим. С некоторым допущением можно о нем сказать, что ассемблер – это язык, позволяющий записать словами те команды, которые непосредственно пойдут на выполнение в процессор.
Итак, у нас есть команда, которую нужно выполнить процессору. Предположим, что надо сложить два числа, одно из которых находится в регистре eax, а второе – в памяти по известному нам адресу. Допустим, адрес задается прямо в команде (такой способ адресации называется прямой или абсолютный). Тогда наша исполняемая команда запишется так:
add eax, 0x0E56
Отметим, что при записи адреса обычно используется шестнадцатеричная система счисления. На вход процессора такая команда, конечно же, подается в виде последовательности нулей и единиц.
Выполнение команды центральным процессором заключается в последовательном прохождении следующих стадий:
1) выборка команды;
2) декодирование команды;
3) выборка операндов;
4) выполнение команды;
5) сохранение результата.
Каждую из этих стадий можно разбить на более мелкие. Они могут быть разными для разных архитектур, но именно такая структура характерна для всех процессоров.
В самом начале нам надо прочитать очередную команду, находящуюся в памяти. Для того чтобы процессор знал, из какого места памяти ему предстоит читать, в нем есть специальный счетчик команд (PC – program counter). В счетчике содержится адрес, по которому процессор читает текущую команду (в нашем случае как раз рассмотренную команду сложения). Команда сохраняется внутри процессора. После этого увеличивается счетчик команд на число, равное длине только что считанной команды.
Следующим шагом происходит декодирование команды. Здесь определяется тип команды, количество операндов и их способ адресации. В нашем конкретном примере процессор понимает, что к нему пришла для выполнения команда сложения. Один операнд для этой команды находится в РОН, он уже есть в процессоре, а второй придется поискать, потому что он лежит в памяти.
Поскольку на прошлом этапе было выяснено, что в процессоре есть не все значения для выполнения команды, то необходимо загрузить их. В нашем случае все оказывается очень просто – у нас есть непосредственно адрес, по которому нам необходимо загрузить операнд. В случаях, когда используются более сложные способы адресации, могут потребоваться дополнительные вычисления адреса операнда. Например, в случае, когда у нас есть базовый адрес и смещение, самый простой пример такого – это массив в языках программирования. Базовый адрес – начало массива, адрес первого элемента, а смещение – это порядковый номер элемента, умноженного на размер элемента. Для вычисления такого адреса в процессоре предусмотрено специальное вычислительное устройство для адресов.
Итак, адрес сформирован, теперь происходит обращение к памяти с запросом данных. Некоторое ожидание – и вот второй операнд появляется в процессоре. Теперь процессор готов произвести расчеты, и наступает следующая стадия: вычисление результата. В АЛУ поступают операнды и расшифрованная команда, которая была определена еще на втором шаге. АЛУ выполняет вычисления и выдает на выход значение, которое теперь остается сохранить.
Место, куда надо сохранить значение, также указывается в команде. В нашем случае оно задано неявно (результат сохраняется на месте первого операнда, то есть в регистре eax). Это достаточно просто сделать, особенно с учетом того, что регистровая память находится ближе всего к АЛУ. Происходит просто запись в регистр полученного значения. На этом команда считается выполненной, и процессор переходит к выполнению следующей команды. Снова повторяются все те же шаги.
Однако, если бы все было так просто, это было бы неинтересно. На самом деле, существует несколько разновидностей команд. Только что рассмотренная команда относится к группе арифметических и логических команд. Существуют еще команды пересылки данных, команды управления потоком команд, команды ввода/вывода и некоторые другие.
Команды пересылки данных предназначены, как несложно догадаться, для передачи данных между различными видами памяти (память-регистр, регистр-регистр, например). Команды ввода-вывода предназначены для того, чтобы предоставить возможность ввести данные в программу (например, с клавиатуры) либо вывести их (например, на экран). Команды управления потоком команд предназначены для изменения последовательности выполнения программы. Дело в том, что все команды программы в памяти располагаются линейно, строго одна за одной. И выполнение их идет так же (вспомните: счетчик PC увеличивается на длину только что считанной команды, как раз до начала следующей). А если в программе встречается команда условного либо безусловного перехода? В случае с безусловным все просто: надо просто загрузить в счетчик команд новый адрес, с которого будем читать следующую команду. В случае с условным, все оказывается намного сложнее. В зависимости от условий либо происходит переход на другой адрес, либо продолжается чтение команд дальше со следующего адреса.
Если подытожить все сказанное, то отметим, что выполнение команды складывается из последовательного выполнения пяти крупных шагов. Кроме того, повторим, что команды бывают разных видов, выполнение одних приводит к вычислению значения, выполнение других позволяет получить данные извне, результатом работы третьих будет перемещение данных внутри памяти и между различными видами памяти.
На сегодня это все. В следующих частях продолжим знакомство с тонкостями и особенностями работы центрального процессора.
Игорь Пацовский
Effective Soft Ltd.
![Версия для печати Версия для печати](https://www.kv.by/sites/all/modules/print/icons/print_icon.png)
Комментарии
Основной вопрос: на какую аудиторию рассчитан этот цикл статей?
IMHO, в расчёте на начинающих нужно излагать более последовательно, а не пугать видами адресации до того, как написана первая простейшая программа. Тем более, что большой разницы для программиста нет в этой классификации: пока не начнёт свой компилятор писать.
И тут я понял, что автор либо говорит не от себя, либо никогда в жизни дела с ассемблером не имел. Команды для ввода с клавиатуры и вывода на экран — это как бы немного круто. Да, через IN и OUT с железяками (включая вышеназванные) можно и иногда даже нужно пообщаться, но, пардоньте!, тогда давайте говорить, что механизм прерываний — это такая штука для MS-DOS, а для выполнения старых программ в Windows процессор переключается обратно в реальный режим. Кстати, как это до сих пор не прозвучало ни слова о режимах процессора?
Упрощение — это даже похвально, но лучше о некоторых вещах вообще до поры до времени не говорить, чем сказать в два слова и создать ложное представление.
Ещё раз поднимаю вопрос о цели и целевой аудитории этого цикла статей.
> Ещё раз поднимаю вопрос о цели и целевой аудитории этого цикла статей.
Cогласен. Для меня - это конспект лекций на первых курсах БГУИР в начале90-х.
add eax, 0x0E56
написано каким-то псевдоязыком. По смыслу далее (суммa eax c содержимым по адресу xxxx) это
либо
add eax, [0E56h] (MASM/TASM/)
либо
add (0x0E56), %eax (AT&T)
либо
add eax, [0x0E56], NASM, ближе всего.
Зачем это было "лепить" в конспект лекции - не знаю.
> Команды для ввода с клавиатуры и вывода на экран
Тоже улыбнуло.
В общем - в лекциях-то не бежали вперед. Тут как деление на 0 - в школе нельзя, а в институте - уже можно. А автор (IMHO) пытается писать "типа институтскую" статью для 5-тиклассников.
>Упрощение — это даже похвально, но лучше о некоторых вещах вообще до поры до времени не говорить, чем сказать в два слова и создать ложное представление.
Угу, и я о том же.
Вот еще "хороший" момент
> Команда сохраняется внутри процессора. После этого увеличивается счетчик команд на число, равное длине только что считанной команды.
Следующим шагом происходит декодирование команды..
В x86 ДО декодирования длина команды (+ операнды и т.п.) - НЕИЗВЕСТНА!
Бывает простота, что хуже воровства.
Ох, а не позавидовали ли наши преданные читатели тому факту, что автор статьи стал призёром мартовского этапа Кофейного конкурса?))
Да ну. Я про это и не думал даже. И вообще, зависть в айтишной тусе, насколько я знаю - явление редкое. Мы же действительно разумные люди. А зависть (плохая которая, в отличие от белой, являющейся стимулом к совершенствованию) подразумевает некоторую убогость ума. Т.е. автоматически отсеивает айтишников-профессионалов.
Согласен c al. Я, кстати, на позапрошлой неделе таки родил статью на 6 страниц Word'а, 14, таймс, полуторный инервал (по профилю, не здешний формат).
2(!) дня убил... + еще пару дней ДО крутил в голове и собирал инфу. Не, такие вещи не для меня... Весьма изредка, разве что. :))
Хе, ещё и издеваццо пытаеццо. Ай молоцца!