Что такое регистр в программировании

Работа с регистрами

Регистры, байты, биты

В этом уроке мы научимся работать напрямую с регистрами микроконтроллера. Зачем? Я думаю в первую очередь это нужно для того, чтобы понимать чужой код и переделывать его под себя, потому что прямая работа с регистрами в скетчах из Интернета встречается довольно часто. Начнём с того, что вспомним, где мы пишем код: Arduino IDE. Несмотря на большое количество не всегда оправданного негатива в сторону этой программы, она очень крутая. Помимо кучи встроенных инструментов и поддержки “репозиториев” от сторонних разработчиков, Arduino IDE позволяет нам программировать плату на разных языках программирования. Это некая условность, но по сути получается три языка:

Что такое регистр? Тут всё весьма просто: это сверхбыстрые блоки оперативной памяти объёмом 1 байт, находящиеся рядом с ядром МК и периферией. На стороне программы это обычные глобальные переменные, которые можно читать и изменять. В регистрах микроконтроллера хранятся “настройки” для различной его периферии: таймеры-счётчики, порты с пинами, АЦП, шина UART, I2C, SPI и прочее железо, встроенное в МК. Меняя регистр, мы даём практически прямую команду микроконтроллеру, что и как нужно сделать. Запись в регистр занимает 1 такт, то есть 0.0625 микросекунды (при частоте тактирования 16 МГц) – это ОЧЕНЬ быстро. Имена регистров фиксированные, полный перечень с подробным описанием можно найти в даташите на микроконтроллер (официальный даташит на ATmega328 – Arduino Nano/UNO/Mini). Работа с регистрами очень непростая, если вы не выучили их все наизусть, потому что названия у них обычно нечитаемые, аббревиатуры. Так называемые “Ардуиновские” функции собственно и занимаются тем, что работают с регистрами, оставляя нам удобную, понятную и читаемую функцию. Ничего сверхъестественного в этом нет. Зачем вообще работать с регистрами напрямую? Есть несколько больших преимуществ:

Но считать значение бита по его названию можно! Причём значение будет равно его номеру в регистре, считая справа. CS11 равен 1, WGM13 равен 4, ICNC1 равен 7 (см. таблицу выше). Думаю здесь всё понятно: есть регистр (байт), имеющий уникальное имя и состоящий из 8 бит, каждый бит также имеет уникальное имя, по которому можно получить номер этого бита в байте его регистра. Осталось понять, как этим всем пользоваться.

Запись/чтение регистра

Существует несколько способов установки битов в регистрах. Мы рассмотрим их все, чтобы столкнувшись с одним из них вы знали, что это вообще такое и как работает данная строчка кода. Абсолютно вся работа с регистрами заключается в установке нужных битов в нужном байте (в регистре) в состояние 0 или 1. Рекомендую прочитать урок по битовым операциям, в котором максимально подробно разобрано всё, что касается манипуляций с битами. Давайте вернёмся к регистру таймера, который я показывал выше, и попробуем его сконфигурировать. Первый способ, это явное задание всего байта сразу, со всеми единицами и нулями. Сделать это можно так:

Только на первый можно посмотреть и сразу понять, что где стоит. Чего не скажешь про остальные два. Очень часто в чужих скетчах встречается такая запись, и это не очень комфортно. Гораздо чаще бывает нужно “прицельно” изменить один бит в байте, и тут на помощь приходят логические (битовые) функции и макросы. Рассмотрим все варианты, во всех из них BYTE это байт-регистр, и BIT это номер бита, считая с правого края. То есть BIT это цифра от 0 до 7, либо название бита из даташита.

Установка бита в 1 Установка бита в 0 Описание
BYTE |= (1 BYTE &=

(1

Использование битового сдвига BYTE |= (2^BIT); BYTE &=

(2^BIT);

Используем 2 в степени (пример не рабочий!)
BYTE |= bit(BIT); BYTE &=

bit(BIT);

Используем ардуиновский макрос bit(), заменяющий сдвиг
BYTE |= _BV(BIT); BYTE &=

_BV(BIT);

Используем встроенную функцию _BV(), опять же аналог сдвига
sbi(BYTE, BIT); cbi(BYTE, BIT); Используем общепринятые макросы sbi и cbi
bitSet(BYTE, BIT); bitClear(BYTE, BIT); Используем ардуиновские функции bitSet() и bitClear()

Можно ещё добавить вариант, где в одной строчке можно “прицельно” установить несколько битов:

Я думаю тут всё понятно, давайте теперь попробуем “прицельно” прочитать бит из регистра:

Чтение бита Описание
(BYTE >> BIT) & 1 Вручную через сдвиг
bitRead(BYTE, BIT) Ардуиновская макро-функция

Два рассмотренных способа возвращают 0 или 1 в зависимости от состояния бита. Пример:

Ещё больше примеров работы с битами смотри в предыдущем уроке по битовым операциям.

16-бит регистры

Такую запись почему-то используют редко, возможно для совместимости с другими компиляторами. Чаще всего вы встретите вот такой вариант, в котором значения “склеиваются” через сдвиг:

Записывать нужно со старшего байта. Как только мы записываем младший байт (последний) – МК “защелкивает” оба регистра в память, соответственно если сначала записать младший – в старшем будет 0, и последующая запись старшего будет проигнорирована.

Источник

Ассемблер. Сегменты памяти и регистры

Обновл. 27 Сен 2021 |

Результат выполнения программы:

Сегменты памяти

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

Сегменты памяти:

Сегмент данных (data segment) — представлен секциями .data и .bss. Секция .data используется для объявления области памяти, где хранятся элементы данных для программы. Эта секция не может быть расширена после объявления элементов данных, и она остается статической во всей программе. Секция .bss также является секцией статической памяти, содержащей буферы для данных, которые будут объявлены в программе позже. Эта буферная память заполнена нулями.

Сегмент кода (code segment) — представлен секцией .text. Он определяет область в памяти, в которой хранятся коды инструкций. Это также фиксированная область.

Стек (stack) — это сегмент, который содержит значения данных, передаваемые в функции и процедуры в программе.

Регистры

Обычно операции с процессором включают в себя обработку данных. Эти данные могут быть как сохранены в памяти, так и извлечены оттуда. Однако процесс чтения данных из памяти и хранения данных в памяти замедляет работу процессора, так как это предполагает сложный процесс отправки запроса данных в блок памяти и получение данных обратно из блока по одному и тому же каналу — через шину управления.

Чтобы ускорить свою работу, процессор подключает определенные внутренние места хранения памяти, которые называются регистрами. Регистры хранят элементы данных для обработки без необходимости получать доступ к памяти. Ограниченное количество регистров встроено в чип процессора.

Регистры процессора

В архитектуре IA-32 есть десять 32-битных и шесть 16-битных процессорных регистров. Регистры делятся на три категории:

Общие регистры (General Registers);

Регистры управления (Control Registers);

Сегментные регистры (Segment Registers).

В свою очередь, общие регистры делятся на следующие:

Регистры данных (Data Registers);

Регистры-указатели (Pointer Registers);

Индексные регистры (Index Registers).

Регистры данных

Регистры данных — это четыре 32-битных регистра, которые используются для арифметических, логических и других операций. Эти 32-битные регистры могут быть использованы следующими тремя способами:

как полные 32-битные регистры данных: EAX, EBX, ECX, EDX;

нижние половины 32-битных регистров могут использоваться как четыре 16-битных регистра данных: AX, BX, CX и DX;

нижняя и верхняя половины вышеупомянутых четырех 16-битных регистров могут использоваться как восемь 8-битных регистров данных: AH, AL, BH, BL, CH, CL, DH и DL.

Некоторые из этих регистров данных имеют специфическое применение в арифметических операциях:

AX (primary accumulator) — используется для ввода/вывода и в большинстве арифметических операций. Например, в операции умножения один операнд сохраняется в регистре EAX/AX/AL в соответствии с размером операнда.

BX (base register) — используется при индексированной адресации.

CX (count register) — хранит количество циклов в повторяющихся операциях (также, как и регистры ECX и CX).

DX (data register) — используется в операциях ввода/вывода, а также с регистрами AX и DX для выполнения операций умножения и деления, связанных с большими значениями.

Регистры-указатели

Регистрами-указателями являются 32-битные регистры EIP, ESP и EBP и соответствующие им 16-битные регистры IP, SP и BP. Есть три категории регистров-указателей:

Указатель на инструкцию или команду (Instruction Pointer или IP) — 16-битный регистр IP хранит смещение адреса следующей команды, которая должна быть выполнена. IP в сочетании с регистром CS (как CS:IP) предоставляет полный адрес текущей инструкции в сегменте кода.

Указатель на стек (Stack Pointer или SP) — 16-битный регистр SP обеспечивает значение смещения в программном стеке. SP в сочетании с регистром SS (SS:SP) означает текущее положение данных или адреса в программном стеке.

Базовый указатель (Base Pointer или BP) — 16-битный регистр BP используется в основном при передаче параметров в подпрограммы. Адрес в регистре SS объединяется со смещением в BP, чтобы получить местоположение параметра. BP также можно комбинировать с DI и SI в качестве базового регистра для специальной адресации.

Индексные регистры

В процессоре существуют 32-битные индексные регистры ESI и EDI и их 16-битные версии: SI и DI. Все они используются в индексированной адресации, и, иногда, в операциях сложения/вычитания. Есть два типа индексных указателей:

Исходный индекс (Source Index или SI) — используется в качестве исходного индекса в строковых операциях.

Индекс назначения (Destination Index или DI) — используется в качестве индекса назначения в строковых операциях.

Регистры управления

Регистром управления является объединенный 32-битный регистр инструкций и 32-битный регистр флагов (регистр процессора, отражающий его текущее состояние). Многие инструкции включают в себя операции сравнения и математические вычисления, которые способны изменить состояния флагов, а некоторые другие условные инструкции проверяют значения флагов состояния, чтобы перенести поток управления в другое место.

Распространенные битовые флаги:

Флаг переполнения (Overflow Flag или OF) — указывает на переполнение старшего бита данных (крайнего левого бита) после signed арифметической операции.

Флаг ловушка (Trap Flag или TF) — позволяет настроить работу процессора в одношаговом режиме.

Вспомогательный флаг переноса (Auxiliary Carry Flag или AF) — после выполнения арифметической операции содержит перенос от бита 3 до бита 4. Используется для специализированной арифметики. AF устанавливается, когда 1-байтовая арифметическая операция вызывает перенос из бита 3 в бит 4.

Флаг переноса (Carry Flag или CF) — после выполнения арифметической операции содержит перенос 0 или 1 из старшего бита (крайнего слева). Кроме того, хранит содержимое последнего бита операции сдвига или поворота.

В следующей таблице указано положение битовых флагов в 16-битном регистре флагов:

Флаг: O D I T S Z A P C
Бит №: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Сегментные регистры

Сегменты — это специфические части программы, которые содержат данные, код и стек. Есть три основных сегмента:

Сегмент кода (Code Segment или CS) — содержит все команды и инструкции, которые должны быть выполнены. 16-битный регистр сегмента кода или регистр CS хранит начальный адрес сегмента кода.

Сегмент данных (Data Segment или DS) — содержит данные, константы и рабочие области. 16-битный регистр сегмента данных или регистр DS хранит начальный адрес сегмента данных.

Сегмент стека (Stack Segment или SS) — содержит данные и возвращаемые адреса процедур или подпрограмм. Он представлен в виде структуры данных «Стек». Регистр сегмента стека или регистр SS хранит начальный адрес стека.

Кроме регистров CS, DS и SS существуют и другие регистры дополнительных сегментов — ES (Extra Segment), FS и GS, которые предоставляют дополнительные сегменты для хранения данных.

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

Пример на практике

Посмотрите на следующую простую программу, чтобы понять, как используются регистры в программировании на ассемблере. Эта программа выводит 9 звёздочек с простым сообщением:

Источник

Уроки FASM. Регистры. Window x32

Что это такое и зачем нужны?

Это самая быстрая память в ПК по сравнению с ОЗУ. Но при этом размер регистров намного меньше чем ОЗУ, по этой причине используют ОЗУ.

Регистр RAX это дополнение EAX, EAX это дополнение AX, AX это объединение 2 регистров AH и AL.

wikipedia

OllyDbg

Ollydbg

Зачем так много разновидностей 1 регистра?

Для поддержке более старых версий процессоров x86 (обратная совместимость, например: на 64 битном ЦП запустить 32 битную программу)

Какие бывают регистры?

Их очень много и каждый под свои задачи, но есть регистры общего доступа, с которыми мы будем работать.

Это 32 битные регистры (16, 8):

ESI (SI, это 16 битный регистр, меньше нет)

EDI (DI, это 16 битный регистр, меньше нет)

Как работать с регистрами?

В них можно хранить любую информацию: числа со знаком (int), числа без знака (unsigned int), числа с плавающей запятой (float, в x64 можно хранить double в регистре), адрес, символы (не превышая размер регистра), и другую информацию.

Попробуем записать значение в регистры:

Что за регистр FLAGS?

Это регистр состояния ЦП, он нужен для проверки и сравнению чисел, проверки регистров.

Источник

Регистры процессора

Начиная с модели 80386 процессоры Intel предоставляют 16 основных регистров для пользовательских программ и ещё 11 регистров для работы с мультимедийными приложениями (MMX) и числами с плавающей точкой (FPU/NPX). Все команды так или иначе изменяют содержимое регистров. Как уже говорилось, обращаться к регистрам быстрее и удобнее, чем к памяти. Поэтому при программировании на языке Ассемблера регистры используются очень широко.

В этом разделе мы рассмотрим основные регистры процессоров Intel. Названия и состав/количество регистров для других процессоров могут отличаться. Итак, основные регистры процессоров Intel.

Таблица 2.1. Основные регистры процессора.

Название Разрядность Основное назначение
EAX 32 Аккумулятор
EBX 32 База
ECX 32 Счётчик
EDX 32 Регистр данных
EBP 32 Указатель базы
ESP 32 Указатель стека
ESI 32 Индекс источника
EDI 32 Индекс приёмника
EFLAGS 32 Регистр флагов
EIP 32 Указатель инструкции (команды)
CS 16 Сегментный регистр
DS 16 Сегментный регистр
ES 16 Сегментный регистр
FS 16 Сегментный регистр
GS 16 Сегментный регистр
SS 16 Сегментный регистр

Регистры EAX, EBX, ECX, EDX – это регистры общего назначения. Они имеют определённое назначение (так уж сложилось исторически), однако в них можно хранить любую информацию.

Регистры EBP, ESP, ESI, EDI – это также регистры общего назначения. Они имеют уже более конкретное назначение. В них также можно хранить пользовательские данные, но делать это нужно уже более осторожно, чтобы не получить «неожиданный» результат.

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

Пока для вас здесь слишком много непонятных слов, но со временем всё прояснится)))

Когда-то процессоры были 16-разрядными, и, соответственно, все их регистры были также 16-разрядными. Для совместимости со старыми программами, а также для удобства программирования некоторые регистры разделены на 2 или 4 «маленьких» регистра, у каждого из которых есть свои имена. В таблице 2.2 перечислены такие регистры.

Вот пример такого регистра.

Из этого следует, что вы можете написать в своей программе, например, такие команды: Обе команды поместят в регистр AX число 1. Разница будет заключаться только в том, что вторая команда обнулит старшие разряды регистра EAX, то есть после выполнения второй команды в регистре EAX будет число 1. А первая команда оставит в старших разрядах регистра EAX старые данные. И если там были данные, отличные от нуля, то после выполнения первой команды в регистре EAX будет какое-то число, но не 1. А вот в регистре AX будет число 1. Сложно? Ну это пока… Со временем вы к таким вещам привыкните.

Мы пока не говорили о разрядах (битах). Эту тему мы обсудим в разделах, посвящённых системам счисления. А сейчас пока вам достаточно знать, что нулевой разряд (бит) – это младший бит. Он крайний справа. Старший бит – крайний слева. Номер старшего бита зависит от разрядности числа/регистра. Например, в 32-разрядном регистре старшим битом является 31-й бит (потому что отсчёт начинается с 0, а не с 1).

Ниже приведён список регистров общего назначения, которые можно поделить описанным выше способом и при этом к «половинкам» и «четвертинкам» этих регистров можно обращаться в программе как к отдельному регистру.

Таблица 2.2. «Делимые» регистры..

Регистр Старшие разряды Имена 16-ти и 8-ми битных регистров
31…16 15…8 7…0
EAX . AX
AH AL
EBX . BX
BH BL
ECX . CX
CH CL
EDX . DX
DH DL
ESI . SI
EDI . DI
EBP . BP
ESP . SP
EIP . IP

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

Источник

MS-DOS и TASM 2.0. Часть 8. Регистры.

Регистры процессора.

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

Изучать регистры процессора мы будем с использованием отладчика TD (Turbo Debugger) и нашей первой программы «Hello, world!» (prg.com). Так что запускаем предустановленный DOSBox и поехали (всё необходимое имеется в архиве DOS-1.rar, который можно скачать с нашего сайта).

Изучаем регистры процессора с помощью TD и нашей первой программы.

Для удобства работы с Turbo Debugger целесообразно увеличить рабочую площадь программы на всё окно.

Используем F5 для увеличения рабочей площади TD.

Регистры процессора Intel и их аналоги.

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

Начиная с 80386, процессоры Intel и их аналоги имеют 16 основных регистров и 11 регистров для работы с числами с плавающей запятой (FPU/NPX) и мультимедийными приложениями (MMX). Для машины всегда быстрее и удобнее обращаться к регистру процессора, чем к памяти.

Помимо основных регистров существуют регистры управления памятью (GDTR, IDTR, TR, LDTR), регистры управления (CR0, CR1 – CR4), отладочные регистры (DR0 – DR7) и машинно-зависимые регистры, которые практически не используются в прикладном программировании.

Регистры процессора 8086.

Так как мы имеем дело с 16 битной операционной системой MS-DOS, то вернёмся во времена процессоров 8086 и 80286. В процессорах следующих поколений указанные регистры являются частями соответствующих 32 и 64 битных регистров с сохранением названия и функционала.

Например, регистр ax (16 бит) является составляющей частью регистра eax (32 бита). Благодаря указанному подходу достигается совместимость работы старых программ на новых компьютерах. Также сохраняются команды и директивы, переходя с 16 битного в 32 битный код.

Итак, процессор (8086 и 80286) содержит 12 16-ти разрядных программно-адресуемых регистров. Регистры процессора принято объединять в три группы:

Кроме этого, в состав процессора входят:

16-ти разрядность обозначает, что в каждом регистре может содержаться 0FFFFh бит информации, то есть два байта: 0FFh-0FFh информации.

Регистры данных (регистры общего назначения).

Регистры данных допускают независимое обращение к старшим (High — обозначается литерой H) и младшим (Lough — обозначается литерой L) половинам.

Источник

Понравилась статья? Поделиться с друзьями:

Не пропустите наши новые статьи:

  • что такое регистр в программировании простыми словами
  • что такое регистр в виндовс
  • Что такое региональная программа
  • что такое региональная программа капитального ремонта многоквартирных домов
  • Что такое ревю в программировании

  • Операционные системы и программное обеспечение
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии