Регистры смещения: Регистры смещения

Регистры смещения

IP
(указатель команд)

SP
(указатель стека)

BP
(указатель базы)

SI (индекс
источника)

DI
(индекс назначения)

В настоящей работе
для нас важен регистр IP. В нем хранится
адрес (смещение) следующей выполняемой
команды. При запуске своих программ не
забывайте следить за его содержимым.

Регистр флагов

Описание этого
регистра Вы найдете в литературе.

Команды debug

Для запуска
программы D e b u g необходимо набрать в
командной строке debug,
на экране появится приглашение «-»
(дефис), в ответ на «?» отладчик
выведет список допустимых команд. Кратко
рассмотрим работу некоторых из них.

Команда R
— позволяет просмотреть все регистры
процессора, или изменить их содержимое:

— RAX

AX = 0000 (старое
значение AX)

: 3A7 (новое
значение AX)

Команда
H

шестнадцатеричная арифметика, например
для выполнения операций сложения и
вычитания двух чисел (B + 1 = С и B — 1 = A)
надо ввести команду:

H
B
1

000C 000A

Команда
Q
— выход из
отладчика.

Команда A
— запись
команд ассемблера в ячейки .

-A 100

1234 : 0100 ADD AX, BX
(в сотую ячейку помещена команда
сложения регистров AX и BX).

Команда E
— ввод данных в память начиная с заданного
адреса.

Команда U
— листинг ассемблерных программ.

Команда T
— пошаговое выполнение программы.

Команда G
— выполнение всей программы (начиная с
адреса в регистре IP) или до заданной
команды. Пусть IP = 100, тогда G104 запускает
программу с адреса 100 до адреса 104.

Команда N
— задает имя
программе: N LAB5.COM.

Команда W
— запись
программы на диск (длина программы в
байтах должна быть помещена в CX, регистры
AX, BX и DX при этом лучше обнулить).

Некоторые команды ассемблера

MOV
AX, BX — переслать число из регистра BX в
регистр AX.

MOV
AX, 123H — записать в AX число 12316.

ADD
AX, BX — сложить содержимое AX и BX.

SUB
AX, BX — вычесть содержимое BX из AX.

MUL BX
— умножить содержимое AX на BX (ответ
помещается в пару регистров — старшие
16 бит в DX, младшие в AX).

DIV
BX — разделить содержимое AX на BX
(ответ помещается в пару регистров —
целое в AX, а остаток в DX).

INT
N — выполнить прерывание N.

Небольшие примеры

1. MOV DX, 41 ;поместим
в DX код буквы A

MOV AH, 02
;поместим в AH номер функции вывода
символа на экран)

INT 21
;прерывание для вывода

INT 20
;возврат в D e b u g

После выполнения
программы на экране появится символ A.

2. MOV AH, 09 ;запишем
в AH 09 — номер функции вывода строки
символов на экран

MOV DX, 0200 ;в DX
поместим адрес начала строки

INT 21
;прерывание для вывода

INT 20
;возврат в D e b u g

Строка будет
печататься до знака $ (доллар). ASCII-код
этого символа — 24H. Код символов выводимой
строки можно поместить в память командой
E200 (при этом данные будут записываться
в память начиная с адреса 200).

Для начала записи
программы выполните команду A.

Что такое регистры? Как с ними работать? / Хабр

Продолжаем рассмотрение базовых вопросов


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

Список статей:

  1. Начинаем изучать STM32 или Управляем светом по-умному
  2. Начинаем изучать STM32: битовые операции
  3. Начинаем изучать STM32: Что такое регистры? Как с ними работать?

Память и регистры


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

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

Каждый из регистров имеет свой порядковый номер – адрес. Адрес регистра обозначается 32-битным числом представленным в шестнадцатеричной системе счисления. Путём записи по адресу регистра определённой комбинации единиц и нулей, которые обычно представлены в шестнадцатеричном виде, осуществляется настройка и управление тем или иным узлом в МК. Вспомним, что в программе для работы с битовыми операциями, мы могли представить в виде шестнадцатеричного числа произвольный набор единиц и нулей. В целом стоит отметить, что существует два вида регистров: регистры общего назначения и специальные регистры. Первые расположены внутри ядра МК, а вторые являются частью RAM-памяти.

Так же стоит отметить, что Reference Manual, который мы скачивали в первом уроке, это один большой справочник по регистрам, содержащимся в целевом микроконтроллере, а библиотека CMSIS позволяет нам оперировать символьными именами регистров вместо числовых адресов. Например, к регистру 0x40011018 мы можем обратиться просто, используя символьное имя GPIOC_BSSR. Конкретные примеры конфигурирования мы рассмотрим в ходе разбора нашей программы из первого занятия.

Итак, обычно структура регистра описывается в виде небольшой таблицы с указанием:

  1. Названия регистра и описания его назначения
  2. Адреса регистра или смещением относительно базового адреса
  3. Значения по умолчанию после сброса
  4. Типа доступа к ячейкам регистра (чтение, запись, чтение/запись)
  5. Значения и описания параметров записываемых битов


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

Разбор кода из первого занятия


Итак, давайте вспомним задачу, которую мы решили на первом уроке используя готовый код примера: нам было необходимо написать программу, которая бы обеспечила попеременное включение двух светодиодов на плате Discovery (возможно и не двух, если у вас другая версия платы Discovery) с временным интервалом.

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

Код main.c

/* Заголовочный файл для нашего семейства микроконтроллеров*/
#include "stm32f0xx.h"
/* Тело основной программы */
int main(void)
{
  /* Включаем тактирование на порту GPIO */
  RCC->AHBENR |= RCC_AHBENR_GPIOCEN;
  
  /* Настраиваем режим работы портов PC8 и PC9 в Output*/
  GPIOC ->MODER = 0x50000;
  
  /* Настраиваем Output type в режим Push-Pull */
  GPIOC->OTYPER = 0;
  
  /* Настраиваем скорость работы порта в Low */
  GPIOC->OSPEEDR = 0;
  
  while(1)
  {
    /* Зажигаем светодиод PC8, гасим PC9 */
    GPIOC->ODR = 0x100;
    for (int i=0; i<500000; i++){}  // Искусственная задержка
          
    /* Зажигаем светодиод PC9, гасим PC8 */
    GPIOC->ODR = 0x200;
    for (int i=0; i<500000; i++){}  // Искусственная задержка
  }    
}


Первым делом, при работе с STM32, даже для такой простой задачи как включение и выключение светодиода нам необходимо предварительно ответить на ряд вопросов:

  1. Куда подключены наши светодиоды? К какому выводу микроконтроллера?
  2. Как включить тактирование на нужный порт GPIO?
  3. Как настроить, нужные нам, пины порта GPIO для того чтобы можно было включить светодиод?
  4. Как включить и выключить светодиод?


Ответим на них по порядку.

Куда подключены наши светодиоды? К какому выводу микроконтроллера?


Для того, чтобы посмотреть где что находится на плате Discovery, а в частности, нужные нам светодиоды — нужно открыть Schematic-файл, либо тот который мы скачали с сайта ST, либо прямо из Keil:


Открыв Schematic мы увидим схему всего того, что есть на плате — схему ST-Link, обвязку всей периферии и многое другое. На текущий момент нас интересуют два светодиода, ищем их обозначение:


Как мы видим, наши светодиоды подключены к порту GPIOC на 8 и 9 пин.

Как включить тактирование на нужный порт GPIO?


В целом, любая работа с периферией в микроконтроллерах STM32 сводится к стандартной последовательности действий:

  1. Включение тактирования соответствующего периферийного модуля. Осуществляется это через регистр RCC путем подачи тактового сигнала напрямую с шины на которой находится данный модуль. По умолчанию тактирование всей периферии отключено для минимизации энергопотребления.
  2. Настройка через управляющие регистры, путем изменения параметров специфичных для конкретного периферийного устройства
  3. Непосредственный запуск и использование результатов работы модуля


То есть, для начала работы нам нужно запустить тактирование на порт GPIOC. Это делается напрямую через обращение к регистру RCC отвечающему за тактирование всего и вся и включению тактового сигнала с шины, к которой подключен наш порт GPIO.

Внимание! Вопрос касательно системы тактирования, её настройки и использования мы подробно рассмотрим в отдельной статье.

Найти к какой шине подключен наш порт GPIOC можно найти в Datasheet’е на наш МК в разделе Memory Mapping в Таблице 16. STM32F051xx peripheral register boundary addresses.


Как вы уже успели заметить, необходимая нам шина именуется как AHB2. Для того чтобы подробнее ознакомиться с регистром, в котором включается тактирование на нужный нам порт GPIO на шине AHB, надо перейти в соответствующий раздел в Reference Manual. По названию регистров мы можем определить тот, который нужен нам:


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


Смотрим на таблицу и видим нечто напоминающее опции включения тактирования на портах GPIO. Переходим к описанию и находим нужную нам опцию:


Соответственно если мы установим 19 бит в значение «1» то это обеспечит включение тактирования на порт I/O C – то есть на наш GPIOC. К тому же — нам нужно включить отдельно один бит из группы, не затрагивая остальные т.к. мы не должны мешать и изменять без надобности другие настройки.

Основываясь на материалах прошлого урока, мы знаем что для того чтобы выставить определенный бит нужно используя логическую операцию «ИЛИ» сложить текущее значение регистра с маской которая содержит те биты которые необходимо включить. Например, сложим значение регистра RCC->AHBENR по умолчанию, т.е. 0x14 и число 0x80000 тем самым включим тактирование GPIOC путем установки 19 бита:

Каким образом мы можем это сделать из программы? Всё достаточно просто. В данном случае у нас два варианта:

  1. Запись в регистр напрямую численного значения регистра напрямую через его адрес.
  2. Настройка с использованием библиотеки CMSIS


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

То есть, мы могли бы обращаться к адресам регистров напрямую по адресу и написать так:

__IO uint32_t * register_address = (uint32_t *) 0x40021014U; // Адрес нашего регистра в памяти	
*(__IO uint32_t *)register_address |= 0x80000; // Включаем 19 бит с нашим параметром


Второй вариант мне кажется наиболее привлекательным, т. к. библиотека CMSIS организована таким способом, что регистру можно обращаться, используя только его название. Препроцессор в ходе обработки текста программы перед компиляцией подставит все цифровые значения адреса регистра автоматически. Давайте разберем этот вопрос чуть подробнее.

Предлагаю открыть наш проект, который мы сделали в первом занятии, или скачайте предварительно подготовленый отсюда и удалите все содержимое программы оставив только подключенный заголовочный файл, функцию main() и инструкцию для включения тактирования (она нам понадобится для подробного разбора кода).

Наш код будет выглядеть следующим образом:

/* Заголовочный файл для нашего семейства микроконтроллеров*/
#include "stm32f0xx.h"
/* Тело основной программы */
int main(void)
{
	/* Включаем тактирование на порту GPIO */
	RCC->AHBENR|=RCC_AHBENR_GPIOCEN;
}


Давайте для ознакомления копнём вглубь библиотеки CMSIS.

Для того, чтобы быстро перейти к месту где объявлена та или иная константа или переменная в Keil реализована удобная функция. Кликаем правой кнопкой по необходимой нам константе, например, на RCC:


И мы переносимся в глубины библиотеки CMSIS, в которой увидим, что все регистры доступные для управления программным способом имеют вид TypeDef-структур, в том числе и наш RCC:


Провалившись подобным образом в RCC_TypeDef мы увидим структуру в которой описаны все поля нашего регистра:


Соответственно, мы можем спокойно обращаться к нужному нам регистру записью вида PERIPH_MODULE->REGISTER и присваивать ему определенное значение.

Помимо мнемонического обозначения регистров есть так же обозначения конкретных битов. Если мы провалимся к объявлению параметра RCC_AHBENR_GPIOCEN из нашей программы, то так же увидим объявление всех параметров:


Таким образом, используя библиотеку CMSIS у нас получается лаконичная читаемая запись нужного нам параметра в регистр, через установку которого мы запускаем тактирование на нужный нам порт:

/* Включаем тактирование на порту GPIO */
RCC->AHBENR|=RCC_AHBENR_GPIOCEN;

В качестве задания: определите используя возможности Keil, каким образом получился адрес регистра RCC->AHBENR как 0x40021014.

Как настроить нужные нам пины GPIO для того чтобы можно было включить светодиод?


Итак, мы знаем что нужные нам светодиоды подключены к порту GPIOC к пинам PC8 и PC9. Нам нужно настроить их в такой режим, чтобы загорался светодиод. Хотелось бы сразу же сделать оговорку, что порты GPIO мы рассмотрим подробнее в другой статье и тут мы сконцентрируемся именно на работе с регистрами.

Первым делом нам нужно перевести режим работы пинов PC8 и PC9 в режим Output. Остальные параметры порта можно оставить по умолчанию. Переходим в Reference Manual в раздел 9. General-purpose I/Os (GPIO) и открываем пункт отвечающий за режим работы пинов порта GPIO и видим что за этот параметр отвечает регистр MODER:


Судя по описанию, для установки пинов PC8 и PC9 в режим Output мы должны записать 01 в соответствующие поля регистра GPIOC.

Это можно сделать через прямую установку с помощью числовых значений:

  1. Формируем число для записи:
  2. Присваиваем это значение нашему регистру:
    /* Настраиваем режим работы портов PC8 и PC9 в Output*/
    GPIOC->MODER |= 0x50000;
    


Или через использование определений из библиотеки:

/* Включаем тактирование на порту GPIO */
GPIOC->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0;


После данной инструкции наши пины PC8 и PC9 перейдут в режим Output.

Как включить светодиод?


Если мы обратим внимание на список доступных регистров для управления портом GPIO то можем увидеть регистр ODR:


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


Для того, чтобы обеспечить попеременную смену состояний светодиодов надо с определенным временным интервалом включать/выключать 8 и 9 биты. То есть попеременно присваивать регистру значение 0x100 и 0x200.

Сделать это мы можем через прямое присвоение значений регистру:

GPIOC->ODR = 0x100; // Зажигаем PC8, гасим PC9
GPIOC->ODR = 0x200; // Зажигаем PC9, гасим PC8


Можем через использование определений из библиотеки:

GPIOC->ODR = GPIO_ODR_8; // Зажигаем PC8, гасим PC9
GPIOC->ODR = GPIO_ODR_9; // Зажигаем PC9, гасим PC8


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

/* Зажигаем светодиод PC8, гасим PC9 */
GPIOC->ODR = GPIO_ODR_8;
for (int i=0; i<500000; i++){}	// Искусственная задержка
					
/* Зажигаем светодиод PC9, гасим PC8 */
GPIOC->ODR = GPIO_ODR_9;
for (int i=0; i<500000; i++){}	// Искусственная задержка


На этом первоначальное знакомство с регистрами и методами работы с ними мы можем закончить.

Проверка результатов работы нашего кода


Небольшое приятное дополнение в конце статьи: в Keil имеется отличный Debug-инструмент с помощью которого мы можем пошагово выполнить нашу программу и просмотреть текущее состояние любого периферийного блока. Для этого после загрузки прошивки после компиляции мы можем нажать кнопку Start Debug Session:


Рабочая среда Keil переключится в режим отладки. Мы можем управлять ходом программы с помощью данных кнопок:


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

Для того чтобы ей воспользоваться — нужно перейти в соответствующий периферийный блок и справа откроется окно с указанием регистров и их значением.


Если вы кликните по одному из пунктов данного меню, вы увидите адрес регистра и его краткое описание. Так же можно просмотреть описание к каждому отдельному параметру регистра:


Попробуйте самостоятельно пошагово выполнить программу, включить/выключить светодиоды не используя программу, а используя данный режим работы с микроконтроллером. Простор для фантазии тут обширный. Так же попробуйте поиграться с длительностями задержек, сделайте одновременное моргание обоими светодиодами. В общем экспериментируйте! )

До встречи в следующих статьях!

Список статей:

  1. Начинаем изучать STM32 или Управляем светом по-умному
  2. Начинаем изучать STM32: битовые операции
  3. Начинаем изучать STM32: Что такое регистры? Как с ними работать?

регистров

регистров


Содержание Вверх << >>


Регистры

В 16-битном режиме, например, в процессоре Pentium при работе в качестве
Virtual 8086 (это режим, используемый, когда Windows 95 отображает приглашение DOS),
процессор предоставляет программисту 14 внутренних регистров по 16 бит каждый
широкий. Они сгруппированы в несколько категорий следующим образом:

  • Четыре регистра общего назначения: AX, BX, CX и DX. Каждый из них является
    комбинация двух 8-битных регистров, которые доступны по отдельности как AL, BL,
    CL, DL («младшие» байты) и AH, BH, CH и DH («старшие» байты). Для
    Например, если AX содержит 16-битное число 1234h, то AL содержит
    34h, а AH содержит 12h.
  • Четыре специальных регистра: SP, BP, SI и DI.
  • Четыре сегментных регистра: CS, DS, ES и SS.
  • Указатель инструкций, IP (иногда называемый программой
    прилавок).
  • Регистр флагов состояния, FLAGS.

Хотя я называю первые четыре регистра «общего назначения», каждый из них
они предназначены для того, чтобы играть определенную роль в общем использовании:

  • AX является «аккумулятором»; некоторые операции, такие как
    MUL и DIV требуют, чтобы один из операндов находился в
    аккумулятор. Некоторые другие операции, такие как ADD и SUB, могут быть
    применяется к любому из регистров (то есть к любому из восьми общих и
    регистры специального назначения), но более эффективны при работе с
    аккумулятор.
  • BX — «базовый» регистр; это единственный регистр общего назначения.
    который может использоваться для косвенной адресации. Например, инструкция
    MOV [BX], AX заставляет содержимое AX сохраняться в памяти
    местоположение, адрес которого указан в BX.
  • CX — регистр «счетчик». Инструкции цикла
    (LOOP, LOOPE и LOOPNE), смещение и вращение
    инструкции (RCL, RCR, ROL, ROR,
    SHL, SHR и SAR), а также строковые инструкции
    (с префиксами REP, REPE и REPNE) все используют
    регистр счетчика, чтобы определить, сколько раз они будут повторяться.
  • DX — регистр «данных», он используется вместе с AX для
    операции MUL и DIV размером слова, а также может содержать порт
    номер для инструкций IN и OUT, но в основном
    доступны как удобное место для хранения данных, как и все другие
    регистры общего назначения.

Ниже приведены краткие описания четырех специальных регистров:

  • SP — указатель стека, указывающий текущую позицию вершины
    стек. Как правило, вы никогда не должны изменять это напрямую, так как
    механизмы вызова и возврата подпрограммы и прерывания зависят от содержимого
    стек.
  • BP — это базовый указатель, который можно использовать для косвенной адресации.
    похож на БХ.
  • SI — исходный индекс, используемый в качестве указателя на текущий отображаемый символ.
    читать в строковой инструкции (LODS, MOVS или CMPS). Это
    также доступен как смещение для добавления к BX или BP при выполнении непрямого
    адресация; например, инструкция MOV [BX+SI], AX копирует
    содержимое AX в ячейку памяти, адрес которой является суммой
    содержание BX и SI.
    916) байт. К
    поддержка машин с более чем 64 КБ физической памяти, Intel
    реализована концепция сегментированной памяти . В любой момент времени
    16-битный адрес будет интерпретироваться как смещение в пределах 64-килобайтного сегмента.
    определяется одним из четырех сегментных регистров (CS, DS, ES и SS).

    Например, в инструкции MOV [BX], AX, упомянутой выше,
    Регистр BX действительно обеспечивает смещение местоположения в текущих данных.
    сегмент; найти истинный физический адрес, по которому содержимое
    аккумулятор будет сохранен, вы должны добавить значение в BX к
    адрес начала сегмента данных. Начальный адрес этого сегмента
    определяется путем взятия 16-битного числа в DS и умножения на 16.
    Следовательно, если DS содержит 1234h, а BX содержит 0017h, то
    физический адрес будет
    1234ч РАЗ 16+0017ч=12340ч+0017ч=12357ч.
    (Это вычисление иллюстрирует одну из причин, почему шестнадцатеричная система счисления так полезна;
    умножение на 16 соответствует сдвигу шестнадцатеричных цифр влево
    место и добавление нуля.) Мы называем этот комбинированный адрес как
    1234:0017 или, в более общем смысле, как DS:BX. 920) памяти. Intel считает
    что этого будет достаточно для приложений 8086 над его
    прогнозируемый срок службы около пяти лет с момента его введения в 1978 году; к
    время, когда микрокомпьютерам требовалось больше мегабайта оперативной памяти,
    следующий процессор Intel (iAPX432) должен был быть доступен с
    32-битное адресное пространство (способно адресовать 4G — более 4 миллиардов памяти
    локации). Однако дебют IBM PC в 1981 г.
    популярность заставила Intel продолжить семейство 80×86
    процессоры, совместимые с предыдущими версиями, включая поддержку
    режим, в котором доступен только 1M памяти. Процессоры со времен
    80286 также предусмотрен «защищенный» режим работы, который в
    Pentium предоставляет каждому процессу плоское 32-битное адресное пространство размером до 4G.

    Вы можете подумать, что регистр сегмента должен будет предоставлять только
    верхние 4 бита, чтобы расширить адрес до 20 бит, но рассмотрим один
    последствия наличия только 16 различных, непересекающихся
    сегментов: каждый сегмент должен был бы занимать полные 64 КБ памяти, даже
    если бы только небольшая часть этого пространства была необходима. Разрешив
    сегмент начинать с любого адреса, кратного 16, память может быть
    распределяется намного эффективнее — если одной программе нужно только 4K для ее
    сегмент кода, то теоретически операционная система может загрузить еще один
    программу в сегмент, начинающийся всего на 4 КБ выше начала первого. Из
    Конечно, MS-DOS на самом деле не настолько сложна, но дизайнеры Intel
    хотел, чтобы это было возможно.

    Каждый сегментный регистр имеет свое особое назначение:

    • CS определяет сегмент «кода»; здесь находится исполняемый файл
      находится код программы. Он не может быть изменен напрямую
      программиста, за исключением выполнения одной из инструкций ветвления. Один
      одной из причин отделения сегмента кода от других сегментов является
      что программы с хорошим поведением никогда не изменяют свой код во время выполнения;
      таким образом, сегмент кода может быть идентифицирован как «только для чтения».
      упрощает работу тайника, так как не требуется никаких усилий для поддержания
      согласованность между кэшем и основной памятью. Он также допускает несколько
      экземпляры одной программы для одновременного запуска (в многозадачном
      операционная система), все они используют один и тот же сегмент кода в памяти; каждый
      экземпляр имеет свои собственные данные и сегменты стека, где информация
      специфичные для экземпляра сохраняются. Представьте несколько окон, каждое из которых работает
      Word в другом документе; каждому нужен свой сегмент данных для
      хранить свой документ, но все они могут выполнять одну и ту же загруженную копию Word.
    • DS определяет сегмент данных; это сегмент по умолчанию для
      большинство обращений к памяти.
    • ES определяет «дополнительный» сегмент, может использоваться вместо DS
      когда необходимо получить доступ к данным из двух сегментов одновременно. В частности,
      регистр DI дает смещение относительно ES при использовании в строке
      инструкции; например, инструкция MOVSB ​​копирует байт
      с DS:SI на ES:DI (а также приводит к тому, что SI и DI
      увеличивается или уменьшается, готов копировать следующий байт).
    • SS определяет сегмент стека; указатель стека SP дает
      смещение текущей вершины стека в сегменте стека. БП
      register также дает смещение относительно сегмента стека по умолчанию,
      для удобного доступа к данным ниже в стеке без
      модифицировать СП. Как и в случае с SP, вам не следует изменять SS, если вы не знаете
      именно то, что вы делаете.

    Указатель команд, IP, дает адрес следующий
    выполняемая команда относительно сегмента кода. Единственный путь
    изменить это с помощью инструкции перехода.

    Регистр состояния FLAGS представляет собой набор 1-битных значений, которые
    отражать текущее состояние процессора и результаты последних
    операции. В 8086 используются девять из шестнадцати битов:

    • Перенос (бит 0): устанавливается, если последняя арифметическая операция закончилась
      оставшийся бит переноса отрывается от левого конца результата. Это сигнализирует
      переполнение на беззнаковых числах.
    • Четность (бит 2): устанавливается, если младший байт последних данных
      операция содержала четное число битов 1 (то есть она сигнализирует
      четное условие четности).
    • Вспомогательный перенос (бит 4): используется при работе с двоичным кодом.
      десятичные (BCD) числа.
    • Ноль (бит 6): устанавливается, если последнее вычисление дало нулевой результат.
      После сравнения (CMP, CMPS или SCAS) это
      указывает на то, что сравниваемые значения были равны (поскольку их разность
      был нулевой).
    • Знак (бит 7): устанавливается, если последнее вычисление дало отрицательный результат (a
      1 в крайнем левом бите).
    • Трассировка (бит 8): при установке переводит ЦП в одношаговый режим,
      как используется отладчиками.
    • Прерывание (бит 9): если установлено, прерывания разрешены. Этот бит
      должен быть очищен, пока процессор выполняет критическую секцию
      код, который не должен прерываться (например, при обработке
      другое прерывание).
    • Направление (бит 10): если сброшено, операции со строками перемещаются из
      младшие адреса в старшие (регистры SI и DI увеличиваются после
      каждый символ). При установке направление меняется на противоположное (SI и DI
      уменьшен).
    • Переполнение (бит 11): устанавливается, если последняя арифметическая операция вызвала
      подписанное переполнение (например, после добавления 0001h к 7FFFh,
      в результате 8000ч; читается как два дополнительных числа, это
      соответствует добавлению 1 к 32767 и получению -32768).

    Существует множество операций, которые будут тестировать и манипулировать различными
    эти флаги, но чтобы получить содержимое всего регистра FLAGS один
    должен поместить флаги в стек (с помощью PUSHF или путем вызова
    соответствующий обработчик прерываний с INT), а затем отключите их
    в другой регистр. Чтобы установить весь регистр FLAGS, последовательность
    реверсивный (с POPF или IRET). Например, один из способов установить
    флаг переноса (есть гораздо лучшие способы, включая STC
    инструкция) выглядит следующим образом:

            ПУШФ
            поп топор
            ИЛИ ТОПОР, 1
            ТОЛКАТЬ ТОПОР
            ПОПФ
     

    Большую часть времени вам не придется иметь дело с регистром FLAGS.
    явно; вместо этого вы выполните одну из условных ветвей
    инструкции, Jcc, где cc — одно из следующих
    мнемонические коды состояний:

    • O, перелив
    • НЕТ, без перелива
    • B, внизу; С, нести; NAE, не выше и не равно
    • Обратите внимание, не ниже; NC, не носить с собой; AE, выше или
      Равный
    • E, равный; Z, ноль
    • NE, не равно; Новая Зеландия, не ноль
    • BE, меньше или равно; NA, Not Above (истинно, если Carry или
      установлен ноль)
    • NBE, не меньше или равно; А, выше
    • S, знак
    • NS, без знака
    • P, паритет; PE, четность по четности
    • NP, без контроля четности; PO, паритет нечетный
    • л, меньше; NGE, не больше и не равно (истинно, если знак и
      Переливы бывают разные)
    • NL, не менее; GE, больше или равно
    • LE, меньше или равно; NG, не больше (истинно, если знак и
      Overflow разные, или Zero установлен)
    • NLE, не меньше или равно; Г, Большой

    Все условия в одной строке являются синонимами. Выше и
    Приведенные ниже условия относятся к сравнению чисел без знака, а Меньше
    и Большие условия относятся к сравнениям со знаком (дополнение до двух)
    числа. Сборка

    : регистр сегментов и регистр смещения

    спросил

    Изменено
    6 лет, 9 месяцев назад

    Просмотрено
    2к раз

    Я немного не понимаю, откуда берется значение 10H? В примере говорится, что ds=1275H (рег. сегмента) и bx:457H (?смещение), почему ds умножается на 10H. И означают ли они, что 1275 — это шестнадцатеричное значение (поэтому десятичное значение равно 4725)?

    • сборка
    • регистры процессора
    • x86-16

    1

    Сегментный регистр указывает на блок памяти 16 байт. ..

    Вот тут и начинается путаница. Сегментный регистр указывает на блок памяти размером 65536 байта, а регистр смещения сообщает, сколько байтов нужно добавить к началу этого 65536-байтового блока. Добавление смещения слова к началу 16-байтового блока не имеет смысла!

    Эти блоки размером 64 КБ сильно перекрываются в памяти. Их начальные адреса отличаются всего на 16 байт! Вы можете рассматривать эти блоки по 64 КБ как формирующие массив, а то, что содержит сегментный регистр, является нулевым индексом для его элементов.

    Таким образом, расстояние между этими блоками является истинным значением 10H, о котором вы спрашиваете.

    Чтобы получить линейный (реальный) адрес ячейки памяти, нам нужно умножить значение в сегментном регистре на 16 (это представлено как 10h в шестнадцатеричном представлении), а затем добавить к нему смещение.

    Ключевыми словами здесь являются «сегментный регистр указывает на 16-байтовый блок памяти».


Опубликовано

в

от

Метки:

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *