ASM >> Немного про работу процессоров с точки зрения языка низкого уровня.

14 июня 2006, среда 20:36
для раздела Блоги
Возникла идея написать небольшой такой цикл статей по процессорам и их работе в компьютере. Зачем?

Я считаю, что любой, кто тесно работает с компьютером, должен разбираться в такой теме. А большинство компьютерщиков-любителей не являются программистами поголовно, а все программистское образование сводиться к изучению Pascal/Basic в старших классах школы или на младших курсах ВУЗа. Поэтому и создается такая ситуация, что людей разбирающихся в комплектухе – много, но при этом мало кто разбирается, как она работает.

Поэтому начнем.

Первое, и самое главное, что стоит уяснить, но о чем большинство и так знают – у процессора в распоряжении есть только один основной ресурс – оперативная память. Можно конечно начинать вспоминать о портах вывода и т.п., но все же подавляющее большинство работы производится над данными в оперативной памяти.

Сама оперативная память – это всего лишь нумерованный массив байтовых ячеек, не более. В них хранятся коды программ и данные. Что важно – в этих ячейках просто хранятся значения от 0 до 255, нигде не указано, данные это или код, это бы было слишком накладно указывать, к тому же что у данных/кода может быть владелец, да и данные могут быть интерпретированы по-разному. Так что для процессора нет никаких переменных, функций и прочего бреда, есть только огромнейший диапазон ячеек, с которого он может читать и писать.

Это конечно, порождает определенные проблемы, поскольку при какой-нибудь ошибке в данных, связанных с командой перехода, процессор может скакнуть на область данных, но при этом, честно интерпретируя её как код программы (а он будет непредсказуем, мягко говоря) и при этом творя кучу «делов». К счастью с помощью особых средств CPU и ОС такие ошибки сейчас вылавливаются в зародыше, но об этом потом.

Кроме того, в процессоре есть специальные ячейки – регистры. Дело в том, что оперативная память крайне медленна (по сравнению с CPU конечно), это обусловлено многими факторами. Два наиболее очевидных – частота памяти меньше чем процессорная, и сама оперативка вынесена за пределы процессора (т.е. нужна связка процессор-память в виде контроллера и шины, что дает дополнительные задержки).

Регистры же находятся в самом процессоре, операция над ними производится с максимально возможной скоростью. Регистры используются для временного хранения отдельных мест оперативной памяти, результатов вычислений, как конечных, так и промежуточных. Размер стандартного регистра (регистра общего назначения, GPR, General Purpose Register) равен 32 битам для 32х-битных процессоров и 64 битам для 64х-битных. Логично, правда?

Самих GPR, впрочем, немного – 8 штук для стандартной архитектуры x86 и 16 для x86-64. Мало? Нет, вполне хватает. Меньшее количество регистров приводит к упрощению кодирования команд, но приходится больше данных хранить в памяти, что естественно резко понижает быстродействие.

Вот собственно и все, что нужно для того, чтобы существовать простейшему процессору, таким собственно и был 8086ой, разве что регистры были поменьше – 16 бит.

Кстати сказать, что в процессоре есть и две других вещи, характеризуемые разрядностью, помимо регистров – это шина данных и шина адреса.

Разрядность шины данных, думаю, в длинном объяснении не требуется – это то количество битов данных, которое может быть передано за такт работы оперативной памяти. Правда, это определение справедливо для SDR – памяти, впрочем, DDR-ом сейчас никого не запу(г/т)аешь и это прекрасно. Правда по отношению к процессору эта разрядность упоминается нечасто, и вряд ли все оверклокеры поголовно скажут, что разрядность одного канала в нынешних процессорах – 64 бита, и это было еще со времен далеких Pentium, за что его иногда называли 64х-битным, что естественно неверно. Разве что относительно недавно придумали эту фишку с двумя каналами, так что при подключении двух планок общая «разрядность передачи данных» увеличивается. Разрядность шины данных может быть в принципе любой, это ограничивается лишь местом на материнке под лишние дорожки проводников, ну плюс общей стабильностью системы (широкую шину труднее заставить стабильно работать).

На видюхах у видеопамяти ширина шины данных куда больше, как и частота, что и обуславливает огромные пропускные способности под 30 Гб в секунду, по сравнению с обычной оперативкой.

Чего-то я разговорился…

Разрядность шины адреса – определяет максимальное число (индекс к ячейкам памяти), которое процессор может выставить. Оно может быть меньше или равно разрядности регистров процессора. Если оно больше, требуются специальные ухищрения, т.к. адрес произвольной ячейки памяти уже не помещается в один регистр (что создает в первую очередь проблемы программистам).

Пример – процессоры 7 поколения (Northwood, Athlon XP итп) – шина 36 бит в специальном режиме, обычно 32, регистры – 32.

Процессоры 8 поколения (Prescott + EM64T, Athlon 64) – адрес 40 бит, регистры 64.

Разрядность шины адреса определяет максимально доступный объем оперативной памяти.
Он будет 2^(разрядность) байт. Ничего сверхъестественного.

На этом, пожалуй, с разрядностями закончим, вернуться всегда успеем.

Теперь, самое важное – данные в регистрах могут интерпретироваться как адрес ячейки памяти. Это фактически тот же указатель в языке программирования высокого уровня, только в своем истинном обличии. Естественно, что адреса мы можем обрабатывать как и обычные числа, что дает нам кучу разных возможностей…

И, наконец, самое главное, о чем я не упомянул ранее – у процессора есть один самый главный адрес, без которого он не может функционировать – это адрес *следующей* исполняемой команды. Он хранится в отдельном регистре, по размерам равному обычному GPR. Для каждой команды он указывает на следующую за ней.

Сами команды кодируются особенным образом, впрочем, формат кодирования пока знать необязательно.

Сами команды обычно имеют до трех операндов включительно. Крайне важно – только один реальный операнд команды может находиться в памяти, все остальное – в регистрах, либо в коде самой команды. Такие уж вот особенности архитектуры x86.

Основные команды это:
mov
add
sub
jmp
jcc

Это перемещение, сложение, вычитание, безусловный и условный переходы. С их помощью уже можно написать практически любую программу. Хотя такая программа будет функционировать, это будет медленно, существует куча дополнительных более удобных команд, но все же основными (и наиболее распространенными вместе с неупомянутой push) являются эти 5.

Каждая команда выполняется определенное число тактов (минимум – 1). Результатом работы команды является изменение значений в регистрах, иногда в строго определенных, иногда в заданных в коде.

Теперь перейдем собственно к самим регистрам.

Здесь я задался вопросом, а какие регистры рассматривать. Традиционно ассемблер начинается с 16-битных программ, но это устарело, т.к. 16-битный режим – это, грубо говоря - DOS. Рассказывать о 64х битном? Прогрессивно конечно, но 64х битность оформлена как обертка над 32х-битным режимом. Поэтому будем рассматривать 32х битные программы.

Для начала осветим такой вопрос – а зачем нам вообще нужны регистры пошире?
Чем больше ширина, тем в большем диапазоне мы можем считать.

Соответственно для регистров шириной 16, 32 и 64 бита это дает
2^16 = ~6E4
2^32 = ~4E9
2^64 = ~1E19
дискретных значений.

При этом работать со значениями превышающими ширину регистра намного труднее и медленнее.

Реальная жизнь ставит реальные задачи – часто ли приходится считать дальше 256?
Конечно! Поэтому восьмибитовые процессоры (которых не было среди x86) плоховато подходили для компьютеров.

А считать дальше 65 тысяч?
Да, вполне, взять те же деньги в игре.

А дальше 4 миллиардов?
Редко, в основном для доступа к различным винчестерам огромного объема и для прочих технических применений, вроде хранения времени в виде количества 100-наносекундных интервалов с начала 17 века до произошедшего события (стандартный формат для windows, кстати ). Здесь можно и помучаться изредка, чем пыхтеть по поводу того, что процессор 32 разрядный.

Но! Так как регистры помимо всего прочего используются еще и как указатель на память… А 4 миллиарда байт, т.е. 4Гб памяти, это не так уж и много. Поэтому, несмотря на отсутствие резкой необходимости в счете обычных величин до 2^64, необходимость в поддержке больших объемов памяти заставила расширяться до 64-х бит. (Надо кстати отметить, что Intel вполне метко назвала новую технологию Extended Memory 64 Technology – EM64T)

Итак, с шириной разобрались. Теперь сами регистры:

Общего назначения:

EAX-аккумулятор (Accumulator)
ECX-счетчик (Counter)
EDX-данные (Data)
EBX-база (Base)
ESP-указатель стека (Stack Pointer)
EBP-указатель базы кадра стека (Base Pointer)
ESI-указатель источника (Source Index)
EDI-указатель назначения (Destination Index)

Дополнительные:

EIP-указатель инструкции (Instruction Pointer)
EFlags-регистр флагов

Причем все начинаются на E, потому что в оригинале – 16-битном, они были без E.

Регистры общего назначения могут меняться программой практически как угодно – команды типа mov, или add могут запросто модифицировать любой из этих регистров. Их названия условны, они означают типичное назначение регистра и восходят к тем временам, когда широко использовались команды, которые использовали регистры именно этим образом, например строковые инструкции, операции ввода-вывода для портов. Сейчас эти инструкции редко употребляются, разве что назначение ESP/EBP все такое же.

Дополнительные регистры могут модифицироваться особыми командами.

EIP модифицируется только командами перехода + процессором при исполнении каждой инструкции.

EFlags – это набор битов, или иначе говоря, флагов, который меняется при выполнении вычислительных операций, чтобы отражать оценку их результата в форме набора битов (присутствие знака, равенство нулю, перенос, переполнение и.т.п.), кроме того здесь же задаются некоторые аспекты работы процессора. Некоторые биты изменяемы с помощью специальных команд.

На этом я, пожалуй, закончу первую часть.

В заключение.

Описываемая мною тема достаточно сложна и многогранна, при этом тяжело балансировать на грани «рассказать меньше/больше чем надо». Я стараюсь, как могу, но если что-то кажется неудачным, неправильным, непонятным и.т.п. – пишите мне в личку (MySte).
Оценитe материал

Возможно вас заинтересует

Популярные новости

Сейчас обсуждают