Архитектура компьютера
Оценка 4.8

Архитектура компьютера

Оценка 4.8
docx
02.02.2023
Архитектура компьютера
Архитектура компьютера.docx

Архитектура компьютера. Физические основы функционирования компьютера. Структура современного компьютера. Ассемблер. Программирование типовых управляющих структур.

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

Рис. 1. Условная модель структуры архитектуры ЭВМ (Источник)

Физические основы функционирования

В основе работы запоминающего устройства может лежать любой физический эффект, обеспечивающий приведение системы к двум или более устойчивым состояниям. В современной компьютерной технике часто используются физические свойства полупроводников, когда прохождение тока через полупроводник или его отсутствие трактуются как наличие логических сигналов 0 или 1. Устойчивые состояния, определяемые направлением намагниченности, позволяют использовать для хранения данных разнообразные магнитные материалы. Наличие или отсутствие заряда в конденсаторе также может быть положено в основу системы хранения. Отражение или рассеяние света от поверхности CD, DVD или Blu-ray-диска также позволяет хранить информацию.

5.     Структура персонального компьютера

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

Персональный компьютер — это настольная или переносная ЭВМ, удовле­творяющая требованиям общедоступности и универсальности применения.

Рассмотрим состав и назначение основных блоков ПК применительно к самым распространенным в настоящее время IBM PC-совместимым компьютерам (см. рис. 3).

Рис. 3. Структурная схема персонального компьютера

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

В состав микропроцессора входят:

·         устройство управления (УУ)—формирует и подает во все блоки машины в нужные моменты времени определенные сигналы управления (управляющие импуль­сы), обусловленные спецификой выполняемой операции и результатами предыдущих операций; формирует адреса ячеек памяти, используемых выполняемой операцией, и передает эти адреса в соответствующие блоки ЭВМ; опорную последовательность им­пульсов устройство управления получает от генератора тактовых импульсов;

·         арифметико-логическое устройство (АЛУ)—предназначено для вы­полнения всех арифметических и логических операций над числовой и символьной информацией (в некоторых моделях ПК для ускорения выполнения операций к АЛУ подключается дополнительный математический сопроцессор),

·         микропроцессорная память (МПП) — служит для кратковременного хра­нения, записи и выдачи информации, непосредственно используемой в вычислениях в ближайшие такты работы машины. МПП строится на регистрах и используется для обеспечения высокого быстродействия машины, ибо основная память (ОП) не всегда обеспечивает скорость записи, поиска и считывания информации, необходимую для эффективной работы быстродействующего микропроцессора. Регистры — быстродействующие ячейки памяти различной длины (в отличие от ячеек ОП, имею­щих стандартную длину 1 байт и более низкое быстродействие); Регистровая КЭШ-память — высокоскоростная память сравнительно большой емкости, являющаяся буфером между ОП и МП и позволяющая увеличить скорость выпол­нения операций. Регистры КЭШ-памяти недоступны для пользователя, отсюда и название КЭШ (Cache), в переводе с английского означает "тайник".

·         интерфейсная система микропроцессора —реализует сопряжение и связь с другими устройствами ПК; включает в себя внутренний интерфейс МП, буфер­ные запоминающие регистры и схемы управления портами ввода-вывода (ПВВ) и сис­темной шиной. Интерфейс (interface) — совокупность средств сопряжения и связи устройств компьютера, обеспечивающая их эффективное взаимодействие. Порт ввода-вывода (I/O — Input/Output port) — аппаратура сопряжения, позволяющая под­ключить к микропроцессору другое устройство ПК.

Микропроцессор, иначе, центральный процессор — Central Processing Unit (CPU) — функционально законченное программно-управляемое устройство обработки информации, выполненное в виде одной или нескольких боль­ших (БИС) или сверхбольших (СБИС) интегральных схем.

Для МП на БИС или СБИС характерны: простота производства (по единой технологии); низкая стоимость (при массовом производстве); малые габариты (пластина площадью несколько квадратных сантиметров или кубик со стороной несколько миллиметров); высокая надежность; малое потребление энергии. Микропроцессор выполняет следующие функции: чтение и дешифрацию команд из основной памяти; чтение данных из ОП и регистров адаптеров внешних устройств; прием и обработку запросов и команд от адаптеров на обслуживание ВУ; обработку данных и их запись в ОП и регистры адаптеров ВУ; выработку управляющих сигналов для всех прочих узлов и блоков ПК. Разрядность шины данных микропроцессора определяет разрядность ПК в целом.

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

·         МП типа CISC (Complex Instruction Set Computing) с полным набором команд;

·         МП типа RISC (Reduced Instruction Set Computing) с сокращенным набором команд;

·         МП типа MISC (Minimum Instruction Set Computing) с минимальным набором команд и весьма высоким быстродействием (в настоящее время эти модели находятся в ста­дии разработки).

Большинство современных IBM PC-совместимых ПК типа используют МП типа CISС - 80586 (Р5) более известных по их товарной марке Рentiuт, которая запатентована фирмой Intel (МП 80586 других фирм имеют иные обозначения: К5 у фирмы AMD, M1 у фирмы Cyrix и др.).

Генератор тактовых импульсов. Он генерирует последовательность электрических импульсов; частота генерируемых импульсов определяет тактовую частоту машины.

Промежуток времени между соседними импульсами определяет время одного такта работы машины или просто такт работы машины,

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

Системная шина. Это основная интерфейсная система компьютера, обеспечивающая сопряжение и связь всех его устройств между собой.

Системная шина обеспечивает три направления передачи информации:

1) между микропроцессором и основной памятью;

2) между микропроцессором и портами ввода-вывода внешних устройств;

3) между основной памятью и портами ввода-вывода внешних устройств (в режиме прямого доступа к памяти).

Основная память (ОП). Она предназначена для хранения и оперативного обмена ин­формацией с прочими блоками машины. ОП содержит два вида запоминающих устройств: постоянное запоминающее устройство (ПЗУ) и оперативное запоминающее устройство (ОЗУ).

ПЗУ (ROM — Read-Only Memory) служит для хранения неизменяемой (постоянной) программной и справочной ин­формации, позволяет оперативно только считывать хранящуюся в нем информацию (изме­нить информацию в ПЗУ нельзя).

Постоянное запоминающее устройство строится на основе ус­тановленных на материнской плате модулей (кассет) и используется для хранения неизме­няемой информации: загрузочных программ операционной системы, программ тестирования устройств компьютера и некоторых драйверов базовой системы ввода-вывода (BIOS — Base Input-Output System) и др.

На современных ПК используются полупо­стоянные, перепрограммируемые запоминающие устройства— FLASH-па­мять. Модули или карты FLASH-памяти могут устанавливаться прямо в разъемы материнской платы и имеют следующие параметры: емкость от 32 Кбайт до 4 Мбайт, время доступа по считыванию 0,06 мкс, время записи одного байта примерно 10 мкс.

Оперативное запоминающее устройство (RAM — Random Access Memory — память с произвольным доступом) предназначено для оперативной записи, хранения и считывания информации (программ и данных), непосредственно участвующей в вычислительном процессе, выполняемом ПК в текущий период времени.

Главными достоинствами оперативной памяти являются ее высокое быстродействие и возможность обращения к каж­дой ячейке памяти отдельно (прямой адресный доступ к ячейке). ОЗУ — энергозависимая память: при отключении напряжения питания информация, хранящаяся в ней, теряется. Основу ОЗУ составляют большие интегральные схемы, содер­жащие матрицы полупроводниковых запоминающих элементов (триггеров). Запоминающие элементы расположены на пересечении вертикальных и горизонтальных шин матрицы; за­пись и считывание информации осуществляются подачей электрических импульсов по тем шинам матрицы, которые соединены с элементами, принадлежащими выбранной ячейке па­мяти.

Конструктивно элементы оперативной памяти выполняются в виде отдельных микрос­хем типа DIP (Dual In-line Package — двухрядное расположение выводов) или в виде моду­лей памяти типа SIP (Single In-line Package — однорядное расположение выводов), или, что чаще, SIMM (Single In line Memory Module — модуль памяти с одноразрядным располо­жением выводов), DIMM (Double In line Memory Module — модуль памяти с двухразрядным располо­жением выводов). Модули DIMM имеют емкость 16, 32, 64, 128 или 256 Мбайт, с контролем и без контроля четности хранимых битов. На материнскую плату можно установить несколько (четыре и более) модулей памяти.

Каждая ячейка памяти имеет свой уникальный (отличный от всех других) адрес. Основная память имеет для ОЗУ и ПЗУ единое адресное пространство.

Адресное пространство определяет максимально возможное количество не­посредственно адресуемых ячеек основной памяти.

Адресное пространство зависит от разрядности адресных шин, ибо максимальное ко­личество разных адресов определяется разнообразием двоичных чисел, которые можно ото­бразить в n разрядах, т.е. адресное пространство равно 2n, где п — разрядность адреса.

Для ПК характерно стандартное распределение непосредственно адресуемой памяти между ОЗУ, ПЗУ и функционально ориентированной информацией.

Основная память компьютера делится на две логические области: непо­средственно адресуемую память, занимающую первые 1024 Кбайта ячеек с адресами от 0 до 1024 Кбайт и расширенную память, доступ к ячейкам которой возможен при исполь­зовании специальных программ-драйверов.

Драйвер — специальная программа, управляющая работой памяти или внешними устройствами ЭВМ и организующая обмен информацией между МП, ОП и внешними устройствами ЭВМ.

Стандартной памятью (СМА — Conventional Memory Area) называется непосредст­венно адресуемая память в диапазоне от 0 до 640 Кбайт. Непосредственно адресуемая память в диапазоне адресов от 640 до 1024 Кбайт назы­вается верхней памятью (UMA — Upper Memory Area). Верхняя память зарезервирована для памяти дисплея (видеопамяти) и постоянного запоминающего устройства. Однако обычно в ней остаются свободные участки — "окна", которые могут быть использованы при помощи диспетчера памяти в качестве оперативной памяти общего назначения.

Расширенная память — это память с адресами 1024 Кбайта и выше. Непосредственный доступ к этой памяти возможен только в защищенном режиме ра­боты микропроцессора.

В реальном режиме имеются два способа доступа к этой памяти, но только при ис­пользовании драйверов:

·         по спецификации XMS (эту память называют тогда ХМА — eXtended Memory Area),

·         по спецификации EMS (память называют ЕМ — Expanded Memory).

Доступ к расширенной памяти согласно спецификации XMS (eXtended Memory Specifi­cation) организуется при использовании драйверов ХММ (eXtended Memory Manager). Часто эту память называют дополнительной, учитывая, что в первых моделях персональных компьютеров эта память размещалась на отдельных дополнительных платах, хотя термин Extended почти идентичен термину Expanded и более точно переводится как расширенный, увеличенный.

Спецификация EMS (Expanded Memory Specification) является более ранней. Согласно этой спецификации доступ реализуется путем отображения по мере необходимости отдель­ных полей Expanded Memory в определенную область верхней памяти. При этом хранится не обрабатываемая информация, а лишь адреса, обеспечивающие доступ к этой информа­ции. Память, организуемая по спецификации EMS, носит название отображаемой, поэтому и сочетание слов Expanded Memory (ЕМ) часто переводят как отображаемая память. Для организации отображаемой памяти необходимо воспользоваться драйвером ЕММ386.ЕХЕ (Expanded Memory Manager) или пакетом управления памятью QEMM.

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

Исключение составляет небольшая 64-Кбайтная область памяти с адресами от 1024 до 1088 Кбайт (так называемая высокая память, иногда ее называют старшая: НМА — High Memory Area), которая может адресоваться и непосредственно при использовании драйвера HIMEM.SYS (High Memory Manager) в соответствии со спецификацией XMS. НМА обычно используется для хранения программ и данных операционной системы.

В современных ПК существует режим виртуальной адресации (virtual — кажущийся, воображаемый). Виртуальная адресация используется для увеличения предоставляемой программам оперативной памяти за счет ото­бражения в части адресного пространства фрагмента внешней памяти.

Источник питания. Это блок, содержащий системы автономного и сетевого энерго­питания ПК.

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

Ассемблер -- это не язык программирования. Это мнемоника команд процессора. Из этого следует что, сколько существует ISA, только и различных ассемблеров.

В курсе рассматривается только архитектура x86, потому что она очень распространенная среди PC и появилась довольно давно, что дает возможность гарантировать работу кода на разных машинах.

Сначала мы рассмотрим x86(32 bit), потом x64 (x86-64 bit)

История процессоров

  • i8086 (1978) -- 16bit
  • i80186 (1982)
  • i80286 (1982)
  • i80386 (1985-1994) -- 32bit
  • i80486 (1989-1994)
  • Pentuim [Pro] (1993 [1995])
  • Pentuim MMX (1997)
  • Pentuim II (порезанный Pro) (1997)
  • Pentuim III (1999)
  • Pentuim M (2003) -- M=mobile
  • Core 2 (2006) -- 64bit

NB) x86 - reg-mem2, cisc

Полезные ссылки

  • www.agner.org - можно найти информацию о производительности на разных архитектурах.
  • www.aida64russia.com - инструмент для тестирования производительности.
  • справка по командам

Обзор регистров

eax = [32bit] = [16bit]:ax (ax -- младшие 16 бит от eax, только для e*x регистров) ax = ah:al (только для *x)

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

Регистры общего назначения (General Proposal)

  • eax - accumulator
  • ecx - counter
  • edx - data
  • ebx - base
  • esi - source index
  • edi - destination index
  • esp - stack pointer
  • ebp - base pointer

Регистры букв важен только в метках

Замечание: лучше всего использовать регистры той битности, что и режим процессора.

Также есть eip (instruction pointer) - в коде мы его не можем использовать. (почти)

EFLAGS - регистр, которые содержит различные флаги.

  • ZF (zero flag) -- нулевой результат вычисления.
  • CF (carry flag) -- знаковое переполнение результата.
  • SF (sign flag) -- знак результата.
  • OF (overflow flag) -- знак беззнакового переполнения.
  • DF (direction flag) -- нужен для особых команд.

Обзор команд

пересылка дынных

mov

mov eax, ebx
mov al, ah
mov ax, [ebx]
mov [eax + ebx * 4], ebx

Что можно писать в скобках:

  • [base_register32 + index_register32 * scale_factor + offset32]
    • base_register32 = general proposal 32-bit register
    • index_register32 = general proposal 32-bit without esp
    • scale_factor = {1, 2, 4, 8}
  • [base_register16 + index_register16 + offset16]
    • base_register16 = {bx, bp}
    • index_register16 = {si, di}

Замечание: Некоторые компиляторы, например yasm, позволяют в скобках писать 5*eax. Они это просто сконвертируют, к верхней схеме, если смогут.

Также иногда необходимо указать размер пересылаемых данных [byte, word, dword]:

mov dword [eax], 5
mov [eax], dword 5

другие

  • xchg -- "swap". Между регистрами почти бесплатный, а по памяти -- дорогая, так как является блокирующей.
  • bswap -- меняет порядок байт (endian)
  • movsx/movzx -- меньшее в большее, первая заполняет знаковым битом, а вторая 0.
  • lea (load effective address) -- вычисляет адрес и записывает его в первые операнд.
  • push/pop -- команды работы со стеком: положить и снять.
  • pushad/pusha -- выгрузить все общие регистры на стек (8 штук); первая для 32битных, вторая -- для 16битных регистров. Порядок, как указано выше.
  • popad/popaa -- снять все регистры со стека. Но esp не запишется.

переходы

  • jmp -- прыгает на указанный адрес, можно передавать регистр. (просто меняет eip)
  • call -- вызывает функцию. То же самое, что jmp ...push eip.
  • ret/ret const -- возврат из функции. То же самое, что pop eip. Вторая команда дополнительно снимает const байт со стека, т. е. то же что pop eip + add esp, const.
  • j__ -- условные переход на метку, в зависимости от состояние флагов. Нельзя передавать регистр. Работает предсказание переходов.
    • c/z/s -- если соответствующий флаг установлен: je label
    • [n] + a/b + [e] -- беззнаковое сравнение(на самом деле просто комбинация флагов после вычитания): jnae label
    • [n] + g/l + [e] -- знаковое сравнение
  • cmov__ -- условная загрузка. Суффикс как выше. Не предсказывается.

арифметика

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

  • add/adc -- сложение/сложение + флаг переноса. (carry flag)
  • sub/sbb -- вычитание/вычитание - флаг переноса.
  • mul rx -- беззнаковое умножение.
    • mul r8 => ah:al = ah * r8
    • mul r16 => dx:ax = ax * r16
    • mul r32 => edx:eax = eax * r32
  • imul -- знаковое умножение
    • imul reg => как выше
    • imul dst, src => dst *= src
    • imul dst, src, const => dst = src * const
  • div/idiv arg32 => edx:eax = (edx:eax / arg32):(edx:eax % arg32) Если результат не влезет в eax будет ошибка переполнения.
  • cwd/cdq -- делает регистровую пару edx:eax/dx:ax, заполняя знаковым битом.
  • inc/dec -- инкремент/декремент. Не меняет флаги.
  • neg - арифметическое отрицание.
  • and/or/xor/not/andn -- побитовые логические операции
    • xor eax, eax -- обнуление eax, это стандартный способ обнуления. Занимает меньше кода, но меняет флаги.
  • cmp/test -- соответствует sub/and, но меняет только флаги. В сочетании с условными переходами позволяет делать условные конструкции.
    • cmp/test + j__ -- часто это одна реальная команда, поэтому не нужно их лишний раз разделять.
    • test eax, eax -- стандартный способ проверки на 0.
  • shr/shl -- логические сдвиги (заполнение нулям), sar/sal -- арифметические сдвиги (заполнение знаковым битом при правом сдвиге, левый сдвиг равен логическому.)
    • последний потерянный бит сохраняется в CF
    • при сдвиге на больше чем 32 будет использоваться только 5 бит
  • shld/shrd -- сдвиги двойной точности. (Можно делить пару)
    • shld reg1 reg2, const -- сдвиг, но потерянные биты беруться из reg2
  • ror/rol -- циклический сдвиг
  • rcl -- циклический сдвиг следующей штуки: (..←[31..0]←[cf]←..)
  • rcr -- циклические сдвиг следующей штуки: (..→[31..0]→[cf]→..)

другое

  • int{x} -- вызвать прерывание, x = 3 -- вывалиться в отладчик.
  • nop -- ничего не делает
  • ud2 -- команда, которая гарантированно отсутствует.

Best practice

модуль числа

  test  eax, eax
  jns   L1
  neg   eax
L1:
 
% но лучше так (нет условных переходов):
  cdq
  xor   eax, edx
  sub   eax, edx

Деление 8

  cdq
  shr   edx, 29
  add   eax, edx
  sar   eax, 3

условные переходы

if(eax == 5 && ebx < 3) {
  X
} else {
  Y
}
  cmp   eax, 5
  jne   LE
  cmp   ebx, 3
  jnb   LE
  X
  jmp   LX
LE:
  Y
LX:

Циклы

do-while

do ... while(eax != 0);

Некоторые конструкции языков C/C++ существуют именно в таком виде, потому что так их можно эффективно реализовать.

L1:
  ...
  test  eax, eax
  jnz   L1

while-do

while(eax != 0) 
    ...
  jz    L2
L1:
  ...
  cmp   eax, 0
  jnz   L1
L2:

switch

switch (eax) {
  case 1:
    X
    break;
  case 3:
  case 4: Y
  case 6: Z
}
    cmp     eax, 6
    ja      LE
    jmp     dword [eax*4 + table]
L1:
    X
    jmp     LE
L2:
    Y
L3:
    Z
LE:
...
    section  rdata
    table  dd LE, L1, LE, L2, L2, LE, L3

Умножение на 10

    lea     eax, [eax*4 + eax]
    add     eax, eax

Деление через умножение

TODO

секции памяти

section .text
  • text -- код.
  • data -- данные.
  • rdata -- данные только для чтения.
  • bss -- неиницализированные данные. Почти не занимаю место в исполняемом файле.

Эти секции описывают свойства процесса. Не путать с сегментами! Они про адресацию.

Calling convention:

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

cdecl

stdcall

pascal

fastcall

Куда класть аргументы?

stack

stack

stack

reg\stack

Порядок загрузки аргументов?

c, b, a

c, b, a

a, b, c

?

Кто снимает аргументы?

caller

calling

calling

?

Где возвращается заначение?

edx:eax/eax/ax

⬅️

⬅️

⬅️

Сохраняемые регистры

ebx, ebp, esi, edi

⬅️

⬅️

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

Как возвращается большие объекты?

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

thiscall

Это нужно для методов классов. Тут тоже пытаются класть this в нулевой аргумент. И поэтому порядок this и *result, если оба необходимо передавать в аргументах, является implementation behavior.

Примеры

  • printf("%s", p) // cdecl
    push  p
    push  fstr
    call  printf
    add   esp, 8
    ...
    section  .rdata
fstr: "%s", 0
  • int f(int a, int b) {return a*2 + b;} // cdecl
; stack = [ret][1st arg][2nd arg]...
    mov   eax, [esp + 4]
    add   eax, eax
    add   eax, [eax + 8]
    ret

cdecl vs stdcall

В stdcall не возможно написать printf, так как это vararg-функция. Такие функции требуют:

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

Best practice

·         Конвенция вызова должна совпадать с конвенцией фукнции. Но это неважно для локальных фукнций, которые никто не будет вызвать, кроме вас.

·         если мы хотим сделать рефакторинг кода на Ассемблере, например, помнять логику программы и делаем push в середине кода, то все адреса стека, к которым обращаются ниже нужно изменить, так как стек сдвинулся. Поэтому удобно писать адрес обращения к аргументам функции из двух часте: mov eax, [esp + 4 + 4], первая цифра -- номер аргумента, вторая -- сколько мы пушнули.

·         Почитать Агнер Calling convention. TODO: добавить ссылку.

FPU/x87

Исторически это сопросцессор, который был сильно разнесен с CPU. Поэтому нет прямого доступа между их регистрами, только через память.

У сопроцессора есть свои регистры: 8 регистров, которые собраны в зацикленный стек.

  • st[0..8]
    • 80 бит (extended presion)
    • Поддерживает разные типы:
      • dword(одинарная точность)
      • qword(двойная точность)
      • tbyte(extended точность)
      • BCD80(что-то с десятичной арифметикой)

Обзор команд

Загрузка

  • fld (from float)
  • fild (from integer)
  • fbld (bcd80)
  • fldpi/fld1/fldz (load pi/1/0)

Выгрузка

  • fst (first store)
  • fstp (fist store and pop)

При загрузке и pop стек крутиться и номера регистров меняются. Но при этом мы не можем затирать значения регистров, которые не освободили. Если это не соблюсти будет NaN.

Арифметические

  • fadd/fsub/fmul/fdiv - общие арифметические операции
  • fprem -- ищет остаток вычитанием, но не более 64 раз, после просто возвращает результат.
  • fabsfchsfsqrtfsinfcosfsincos (ищет оба и кладет на стек.)
  • fcom -- сравнение и запись во флаги сопроцессора, поэтому нельзя делать бранчи с этой командой
  • fcomi -- сравнение + запись в CF, ZF. OF не записывается! jne - не работает

Другие

  • finit - помечает все регистры как доступные и устанавливает дефолтное значение.
  • fchx st1 (swap st1, st0)
  • [command] + ..r = [command with reverse order of argument]
  • [command] + ..p = [command with pop before load result]
  • ffree -- освободить регистр.
  • fincstp/fdecstp -- покрутить стек.
  • fisttp -- выгружает значение из регистра и выкидывает его со стек. При этом значение конвертится к целому числу отбрасыванием дробной части.

Calling convention

  • Вызванная функция должна зачистить стек командой finit перед использованием x87.
  • Если возвращаемое значение функции имеет вещественный тип, то оно кладется на вершину стека (st0). Это верно для любой конвенции 32битного мира.

Best practice

  • про конвертацию между целыми и вещественными числами: (касается не только x87)
    • Долго конвертировать uint в float, так как надо сделать проверки переполнения.
    • Долго конвертировать float в int, так как не совпадают стандартные округления: в C к 0, в asm к ближащему четному (default). Поэтому нужно переключить режим окргуления, а это долго.
    • Лучше не использовать ассемблерные вставки, так как это не переносимо: из-за компиляторазависимиого синтаксиса, а также msvc вообще не поддерживает их под 64bit. Поэтому лучше писать на ассемблере отдельные функции в отдельных файлах.

Пример: Как вызвыть функцию на asm, из кода C/C++:

// declaration
// C
float __cdecl arctan(float x, int n);
// C++ 
extern "C" // for name mangling
float __cdecl arctan(float x, int n);

SIMD-команды

SIMD - single instruction, multiple data. Это идея когда мы можем одной командой обрабатывать сразу несколько ячеек данных.

История расширений Intel для SIMD и не только. TODO

  • MMX (Pentium MMX, 1997) : mm0..7 - 64 бита мантисы регистров FPU, можно использовать для int. И обрабатывать сразу два int одной командой
  • SSE (Pentium III, 1999) : xmm0..7 - 128 битые регистрые, которые можно использовать как 4 float. Плюс, что это никак не связано с FPU, про который пытаются забыть.
  • SSE2 (Pentium 4) : можно использовать xmm для int.
  • SSE3 (later Pentium 4) : доп. команды.
  • SSE4 (early Core 2, 2006) : доп. горизонтальные команды.
  • SSE4.1 (later Core 2, 2008) : ...
  • SSE4.2 (2008) : ...
  • SSE4a (...) : ...
  • AVX (2012) : ymm - 256 битные регистры, но только для float
  • AVX2 (2013) : можно использовать ymm для int
  • AVX512 (2015) : zmm - 512 битные регистры
  • FMA3, FMA4 (2010) : fused multiply-add, инструкции типа a*b + c для x\ymm. Фича: округление происходит только один раз.
  • AES_NI (2008) : Advanced Encryption Standard New Instruction
  • BMI(2013) : bit manipulation instruction, добавились команды для некоторых логических выражений типа: ~x & x-x & xx & (x - 1).

MMX

Так как эти регистры накладываются на регистры x87, их нельзя использовать одновременно. Во время работы с mmx, все st помечаются как недоступные, и в конце нужно вызвать команду emms, которая пометит все st0..8, как доступные к использованию.

Замечание: Эта команда сильно похожа на finit, но последнаяя также устанавливает дефолтное значение.

Обзор Комнад (TODO Annotation)

·         movss - (SSE) load scalar single precision.

·         movap{s, d} - (SSE) load aligned packed single/double precision. Каждый из двух операндов может быть или памятью, или регистром. Память должна быть выровнена до 16 байт.

·         movup{s, d} - (SSE) load unaligned packed single/double precision. Тоже что выше, но память может быть не выровнена.

·         punpckl{bw, dq, qdq, wd} - unpack low data. {bw} - собирает word из byte, используя младшую часть регистов. Схема

·         punpckm{bw, dq, qdq, wd} - unpack high data. {bw} - собирает word из byte, используя старшую часть регистров. Схема

·         packss{wd, dw} - pack with signed saturation. Saturation - число конвертиться в число меньшей битности, так чтобы значение было ближе всего к исходному. Схема

·         packus{wd, dw} - pack with unsigned saturation.

·         pmulhw - multiply packed signed integer and store high result.

·         pmullw - multiply packed signed integer and store low result.

·         pmaddwd - multiply and add packed integer. Схема

·         pcmpeq{b, w, d} - Compare packed data for equal.

·         pcmpgt{b, w, d} - Compare packed signed Integer for greater than

·         pand/por/pxor/pandn - bitwise and/or/xor/and not

·         psrl{w, d, q} - Shift packed data right logical Схема

·         psra{w, d, q} - Shift packed data right arithmetic Схема

·         psll{w, d, q} - Shift packed data left logical. Схема

·         paddus{b, w} - add packed usigned intgers with unsigned saturation.

·         psubus{b, w} - sub packed usigned intgers with unsigned saturation.

·         palignr dst, src, imm8 - конкатенирует dst и src, потом сдавигает в право imm8 байт и записывает младщую часть в dst.

·         pshufw dst src imm8 - Shuffle the words in src based on the enocoding in imm8 and store the result in imm1. Схема

·         emms - Очищает все x87 регистры

·         movq/movd -- загрузить целочисленный qword/dword

Выравнивание

Как сделать выравнивание данных в asm?

  • на стеке
            section .data
            align 16
            const1: 12 
  • в куче
    • alloc + ручное выравнивание
    • align_alloc(Linux)/virtual_alloc(Windows)

Выравнивание стека

Перед любым вызовом функции в 32 битах жилательно выравнивать стек до 16, а в 64 битности - это обязательно.

Выделить n байт с выраниванием 16

            push   ebp
            mov    ebp, esp
            sub    esp, n
            and    esp, -16
            ...
            mov    esp, ebp
            pop    ebp

История про разгон кода

TODO

Режимы работы процессора (16 и 32bit)

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

Режим работы меняет коды команд.

  • real 16
  • protected 16/32/v86
  • long mod 64/compatibility32/compatibility16

Биос начинает работать в real mode и потом постепенно переходит в нужный.

Real mode

Изначально в этом режиме работали 16 битные процессоры.

Адресация

В i80186 можно адресовать 1 Мб оперативки, то есть 220

Физический адрес = сегмент * 16 + смещение(виртуальный адрес)

Сегментный регистрыcs(code), ds(data), ss(stack), es(extra). Они тоже состоят из 16 бит и могут хратить любой адрес.

Сегмент можно указывать явно,

mov al, [ebx] ; по-умолчанию
 
mov al, ds:[ebx]
 
ds: ; seg ds
mov al, [ebx]

а может выводиться по-умолчанию:

  • команды, которые всегда работают стеком(pop, push) используют ss
  • для адреса команд аналогично cs
  • для памяти мы смотрим регист, который используется как база:
    • bpebpesp => ss (sp нет, потому, что его не бывает в квадратным скобках.)
    • Остальные к ds.
  • В некоторых командах есть свои умолчания.

Ограничение на размер сигмента Существует ограничение на размер сигмента 64Kb. Но его можно обойти написав сегмент ясно ds:[eax]. Важно также заметить, то в real mode можно использовать 32битные регистры для адресов начиная с i80386. Замечание: В "C" есть поэтому поводу оговорка, что объект не может занимать больше места чем максимальный размер смещения. (< 64kb)

Замечание:

mov al, [ebx + ebp] ; implementation undefined behavior
 
mov al, [ebx + ebp*1] ; ok, => ds
; хороший компилятор (not nasm) позволяет таким образом подавить использование ebp как базы

i80286

Может адресовать 24-битные адреса.

Добавились новые сегментные регистры: fsgs с неопределенным использованием.

A20 line: в i80186 при обращении за границы 1 Мб происходило переполнение. То есть всегда использовались только последние 20 бит. А в i80286 можно адресовать большую память, поэтому переполения не происходило и можно было адресовать 220+216−24 в real mode. Для обратной совместимости можно влючить переполнение. Про это Bios Line 20 disable

Проблемы Real Mode

  • Нельзя управлять памятью.
    • Невозможно безопастно делить ее между процессами.
    • Отделять код системы от кода пользователя.

Protected mode 16

Это режим появился в 286.

Теперь сегментный регистр содержит не базу сегмента, а селектор, который состоит из 3 частей.

[0..1] <- RPL
[2] <- G/L
[3..15] <- index

·         index - индекс дескриптора сегмента в глобальной таблице.

·         g/l - global/local description table, но локальные не используется.

·         rpl - права

    • 0 - макс. права
    • 3 - мин. права

Дескриптор сегмента состоит из 8 байт и содержит все необходимую информацию о сегменте:

  • Базу
  • Лимит
  • Флаги
  • Уровень привелегий.

Адрес таблицы дескрипторов храниться в регистре gdtr (global description table register).

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

Права

Теперь у нас есть 4 уровня прав. 0 - уровень ОС. 3 - уровень пользователя.

Это позволяет:

  • Разграничить пользовательский код и код ОС.
  • Ограничить доступ пользователя к данным.

CPL - current privilege level - уровень прав в регистре cs. Он пределяет права кода. В этом отличие пользовательского кода, от кода OC.

RPL - request privilege level - уровень прав в остальных сегментных регистрах, который определяет права для запроса на использование своего дескриптора.

DPL - descriptor privilege level - уровень прав в дескрипторе сегмента.

  • Если это сегмент кода, то это уровень привелегий это кода.
  • Если это сегмент данных, то уровень привелегий определяет, кто может обращаться к этим данным.

Замечание: Зачем нужен RPL, если есть DPL? Когда мы передаем управление более привелегированному коду и просим его, например, изменить данные сегмента, на который у нас прав нет. Тогда вызваемая функция может записать в RPL селектора, записать наш CPL. Так как при обращении к данным сверяется с DPL не только CPL, но и RPL, данные будут защищены.

Существуют инструкции в защищенном режиме можно использовать только при нулевом CPL.

Процесс может понизить свои права. Но как повысить?
Мы можем вызвать прерывание, у которого выше уровень привилегий. И он может вернуть нам права.

Адресация

Защита достикается повышением абстракции. Теперь адреса бывают:

  • логические(logical) - пара <сегмент>:<смещение>
  • линейные(linear) - промежуточный уровень(нужен для страничной адресации) = <сегмент> + <смещение>
  • физические(physical) - адрес, который подается в шину. <физческий адрес> = <линейный> (пока нет страничной адресации)

В 286 база сегмента составляла 24 бита, поэтому максимальная доступная память - 224 = 16 Mb. При этом длина сегмента менялась от 1 до 216 байт.

Переходы:

  • Ближние jump, call -- в приделах одного сегмента памяти.
  • Дальние: far_jump, far_call -- меняет также сегмент кода. jmp segment:offset

Flat-модель памяти.

Это идея обращения процесса с памятью. Она заключается в том, что память для процесса - это единое и не делимое пространство.

32bit защищенный режим

Это режим появился в 386. В нем увеличилась битность линейного адреса до 32 бит и появилась возможность делать сегменты с лимитом 4Gb. Это открыло доступ к Flat-module работы с памятью.

Размер дескриптора при этом не поменялся, так как в нем заранее присутствовали 2 неиспользуемых байта.

Также в дескрипторе есть флаг, который для сегмента кода значит, какой битности записаны команды: 16 или 32. (D-bit)
Подробнее о флагах на вики

Замечание: Теперь лимит не может принимать любые значения, так как он занимает всего 20 бит и увеличивается за счет изменения гранулярности с 1 байта на 4Кб.

Unreal mode

Существует незадокументированная фича, что при переходе в real mode теневая часть не меняется. Это дает доступ к сегментам большого размера в реальном режиме. Это называют нереальном режимом. (unreal mode)

Так как в real mode можно использовать 32 битные регистры, то можно получить доступ к 4Gb. Это фича называется Operand Size Override Prefix и включается отдельно(может добавляться автоматически компилятором ассемблера). И важно отключить вентиль A20.

TODO: Проверить: Видимо лимит на размер сегмента в реальном моде даже на i80186 хранился в скрытой части сегмента(видимо тогда она уже сущетсвовала.). Но я не нашел явно упоминания.

возможно лимит не надо было хранить, так как он всегда один и тот тоже.

v86

Режим совместимости с 8086. Адресация как в реальном режиме, но с кольцами прав.

SMM

System Management Mode - режим отладкиwiki

Страничная адресация

Это новый способ адресации, который был введен с 386.

Замечание: Почему на некоторых Win32 нельзя выделить больше 4 ГБ?
Это лишь лицензионное ограничение. На самом деле благодаря страничной адресации мы можем выделять довольно большое адресное пространство для программы. Так как система сама строит адресное пространство.

AWE - другой хак, который позволяет выделять процессу больше чем 4ГБ без страничной адресации.

Замечание: AWE(Address Windowing Extension) - суть заключается в окне в адресном пространстве программы, которое мы можем отображать в разные части пространства физических адрессов.

Замечание: Страничная адресация работает на уровне MMU. Но настраивается на уровне процессора.

Теперь все пространство поделяно на страницы(page) по 4Kb.

Страница описывается структурой из 4 байт PTE(page table entry).

Одна страница в которой лежат эти структуры ($2^{10}$ штук) называется Page Table.

Одна такая Page Table описывается структурой в 4 байта PDE(page directory entry)

И эти структуры лежат в Page directory, адрес на которую лежит в CR3. (Control register)

  • [10, 10, 12]
    • Первые 10 - индекс в page directory.
    • Вторые 10 - индекс в page table, адрес, который мы нашли в page directory.
    • Последние 12 - cмещение в page (не изменяется при трансляции)

У каждого процесса своя иерархия, у каждого есть своя ссылка на свою page directory.

Feature:

·         Каждая программа имеет в распоряжении 4Gb. Но физическое пространство такое же.

·         Есть куча флагов на разных уровнях иерархии, поэтому мы можем управлять памятью.

·         Ленивое выделение - страница реальная отобразиться в память когда она нужна.

·         Почти отсутсвие дефрагментации.

·         Разделяемые библиотеки. Разные процессы мапят одну и ту же память, которая содержит библиотеку. Каждый процесс мапит в свой виртуальные адрес. Эта память находиться в read-only. Если вдруг кто-то захочет поменять код библиотеки, то случается page-fault. Потом процессор копирует нужные страницы и ставит write permission. То есть в режиме copy-on-write.

·         swap(paging): swap - выгрузка всего дампа (сейчас редкость), paging - выгрузка части. Сброс страниц оперативки в память. Если страница долго не используется, то ОС выгружает ее, если мы хотим обратиться к ней, то она вгружается.

TLB: Мы получили очень гибкий механизм, но долгий. Поэтому сущетсвует TLB(translation lookaside buffer)-кеш.
Но не все так просто: при переключени ядра на другой процесс нужно его сбрасывать. При этом остальный кешы процессора (L1, L2, L3) сбрасывать не надо, так как они хранят только физические адреса.
Так же TLB можно использовать в уязвимости Meltdown.

Замечание: Традиционно первые сколько-то адресов не замапленые в никуда, это сделано, чтобы null-pointer падал гарантированно. Он просто идет в page directory и там написано, что не замапалено.

Замечание: Бывает спекулятивное подгрузка страниц. Можно посмотреть на Аиде, которая может вырубать это на работающем процессе, что посмотреть что поменяется.

Что делать если у нас оперативки больше, чем 4GB? Расширения:

  • PSE (page size extension): добавляется возможность создавать большие страницы по 4Mb. Для их меняется PTE, но не PDE, поэтому можно использовать и маленькие, и большие страницы.
  • PAE (physical address extension): Мы делаем структуру, которая описывает страницу жирнее не 32 бита а 64, чтобы адресовать больше адресов. Из-за этого меньше page table, поэтому есть еще один уровень. [31..30, 29..21, 20..12, 11..0] = [2, 9, 9, 12]
    • Это позволяет сильно увеличить ограничение на размер физической памяти.

Адресное пространство делиться на системное и не системное. Это определяет по первому старшему биту. Для 32 битных адресов: младшие 2ГБ - user space, старшие 2ГБ - kernel space.
Так сделано для удобства работы ОСи. Например, чтобы понимать у каких данных нужно проверять права доступа.

Замечание: Поэтому для 32битных приложений все равно полезно 64битная операционка, так тогда оно получит не 2ГБ, а 4ГБ.

Режимы работы процессора (64bit)

Зачем нужен 64bit?

  • Чтобы увеличить виртуальное адресное пространство.
    • Это важно при file-mapping.
    • При увеличении адресного пространства уменьшается его фрагментация.

Long mode (64битный мир)

От сегментной адресации не осталось почти ничего еще в 32bit режиме. Кроме:

  • в cs осталось кольцо прав
  • в дескрипторе cs указывается битность сегмента, которая определяет битность режима.

Остальные сегменты получили базу 0, и лимит максимальный - 4Gb. Тем самым смещение виртуального адреса совпадает с линейным, который потом транслируется в физический через страницы.

Что с fsgs? От них осталось поле базы.

  • fs -- обычно используется для thread local storage
    • Пример: winapp и может показать последнюю ошибку last_error(), но это работает и при нескольких тредов. Потому, что они хранятся локально для каждого треда.
    • fs указывает к каждом треде на разное смещение в TEB(thread enviroment block), из который уже узнается настоящий адрес переменной.
    • Linux используется для тех же целей gc
  • В Win32 - TEB32, Win64 - TEB64. Поэтому там используется и gc(64), и fs(32).

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

Режимы совместимости.

16/32 битный код не переключается обратно из long mode, для этого у него есть свои подрежимы(compatibility mode).

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

Как работает 32битная программа на 64 битной в Windows.

Есть системные библиотеки под каждую битность. Когда 32-битный код делает системный вызов, то вызывается NTDLL32.dll, которая делает far_call к NTDLL64.dll. Тем самым 32-битный код вызвает 64-битные системные вызовы.

Canonical address

Во всех текущих процессорах x64 не используются все 64 бита виртуального адреса. Так как пока 264 слишком много для текущих требований, то из соображений оптимизации не все биты адреса транслируются. Только младшие 48 бит учавствуют в трансляции, что позволяет адресовать 256 TB. Учитывая деление виртуального пространства на user space и kernel space получаем доступный диапазон: 00000000'00000000..00007FFF'FFFFFFFF + FFFF8000'00000000..FFFFFFFF'FFFFFFFF

x32

Это подсистема(ABI) linux, которая позволяет работать в 64битном мире, но указатели размером 32бита. Иногда это полезно. Так тогда мы получаем полезности 64битного режима, но не платим за это размером указателей.

Картинка переключения режимов

  • EFER.LME - long mode enable
  • CR4.PAE - включить pae-расширение страничной адресации
  • CP0.PG - включить paging (возможности сбрасывать страницы в память)
  • CP0.PE - protected mode enable
  • EFLAGS.VM - virtual-8086 mode
  • CS.L - флаг дескриптора сегмента CS, который отвечает за 64-битность сегмента, при этом флаг D должен быть равен 0.

Замечание: Необходимо помнить, что переключени режимов - это привелегированная операция, а подрежимов - нет.

64-битный мир

История

AMD выпустили новую ISA, которая полностью поддерживала x86 и назвали ее AMD64. Потом Intel ее поддержал. Другие названия: x86-64, x64

Изменения по сравнению с x86

  • Расширение общих регистров до 64 бит. (raxrbx ...) 32битные названия - это их младшие части.
  • у регистров esiediebpesp появилась возможность обращаться к их младшей части. (rsi -> esi -> sih:sil)
  • новые регистры общего назначения r8..15 (r9 -> r9d -> r9w -> r9bЗамечание: TODO: более четко сформулировать
            mov al, bh % ok
            mov r9b, bh % нельзя, так как коды таких команды отданы под sil, dil

Адреса TODO

  • выражения в скобках [base_register + index_register * scale_factor + off32]
    • base_register - raxrcx, ... r15
    • index_register - rax, ..., rsp, ..., r15
    • scale_factor - 1, 2, 4, 8
    • off32 - это знаковая константа. И ее битность являет проблемой. Метки перестают работать, так как их адрес стал 64битным, а в схеме мы не может это указать.
  • Можно использовать rip для указания смещения по коду.
    • mov reg, [rip + const32] TODO
    • mov reg [rel label], компилятор приводит это к тому, что выше.
    • написать default rel, чтобы дать указание компилятору все обращения к меткам приводить код строчке выше.

Так

  • Исключения из схемы
    • mov acc, [offset64] - только для alaxeaxrax.
    • mov r*, const64

Фича с обнулением

mov eax, ecx - обнуляет старшие 32 бита.

Это позволяет избежать больших констант, то есть больших кодов команд.

Замечание: У команды nop такой же код, как у команды xchg eax, eax. Поэтому в этом случае старшая часть не зануляется.

            xchg     eax, eax % нет зануления
            xchg     ebx, ebx % есть зануление

Замечание: Вместо xor rax, rax лучше писать xor eax, eax, так как занимает меньше места.

XMM

Добавили xmm8..15. А про mmx стараются забыть.

Выкинули команды.

  • aaaaadaamaasdaadas - 10ичная арифметика.
  • boundinto - что-то с проверкой границ.
  • pushad/popad - выгрузить все.
  • los/les - что-то с сегментами.
  • push/pop {cs, ds ...}
  • jmp/call для абсолютного адреса.
  • short form of inc/dec - теперь кодируется только в полную форму, старая занимала 1 байт.
  • sysenter/sysexit - intel команды для системного вызова.

Calling convention in x64

  • Во всех конвенция теперь обязательно перед вызовом функции выравнивать стек до 16.

Fastcall64 (Windows)

Порядок передачи аргументов.

  • rcxrdxr8r9
  • xmm0xmm1xmm2xmm3
f(int a, float b, int *c);
// a -> rcx
// b -> xmm1
// c -> r8

Возвращаемое значение

  • целое в rax или в rdx:rax для 128 бит.
  • вещественное в xmm0

Методы

this передается также(в нулевой аргумент)

сохраняемые регистры

rbxrbprsirdir12..15xmm6..15

Замечание: сохранение xmm большая проблема.

Фича: Shadow space

Она заключается в том на стеке всегда выделяется 32 байта вне зависимости от количества аргументов. Оно нужно для того, чтобы скинуть все аргументы на стек.

stack -> [ret][shadow space][other args]...

Это может быть полезно для variadic-функции, чтобы единообразно их обрабатывать.


без названия (Unix)

Порядок передачи аргументов.

  • rdirsirdxrcxr8r9
  • xmm0..7 в rax записанно сколько загруженных xmm
f(int a, float b, int *c);
// a -> edi
// b -> xmm0
// c -> rsi
// rax = 1

Возвращаемое значение

  • целое в rax или в rdx:rax для 128 бит.
  • вещественное или комплексное в xmm0:xmm1

Методы

this передается также(в нулевой аргумент)

сохраняемые регистры

rbxrbpr12..15

Фича: Red zone

Она заключается в том, что мы можем писать на 128 байт ниже rsp.

Это может быть полезно для последний функции.

Про что здесь не сказано:

  • Локальные метки: может быть удобно, но компиляторозависимо.
  • Макросы: тоже, что и локальнымим метками.

НЛО TODO

1

NB) Есть две таблицы: - таблица, для всего, ее используется система. - урезанная таблица, для процесса. При syscall, мы переходим в код ядра, с полными таблицами.

СТРУКТУРНОЕ ПРОЕКТИРОВАНИЕ И ПРОГРАММИРОВАНИЕ

Нисходящее проектирование

Метод нисходящего проектирования предполагает последовательное разложение общей функции обработки данных на простые функциональные элементы ("сверху-вниз").

В результате строится иерархическая схема, отражающая состав и взаимоподчиненность отдельных функций, которая носит название функциональная структура алгоритма (ФСА) приложения.

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

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

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

Разложение должно носить строго функциональный характер, т.е. отдельный элемент ФСА описывает законченную содержательную функцию обработки информации, которая предполагает определенный способ реализации на программном уровне.

Функции ввода-вывода информации рекомендуется отделять от функций вычислительной или логической обработки данных.

По частоте использования функции делятся на:

  • однократно выполняемые;
  • повторяющиеся.

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

Пример 18.4. Некоторые функции, например Ф2, далее неразложимы на составляющие: они предполагают непосредственную программную реализацию.

Другие функции, например Ф1, Фm, могут быть представлены в виде структурною объединения более простых функций, например Ф11, Ф12 и т.д. Для всех функций-компонентов осуществляется самостоятельная программная реализация; составные функции (типа Ф1, Фm) реализуются как программные модули, управляющие функциями-компонентами. например, в виде программ-меню.

Рис. 18.2. Функциональная структура приложения:

Ц - цель; пЦ - подцель; П - приложение; Ф - функция

МОДУЛЬНОЕ ПРОГРАММИРОВАНИЕ

Свойства модуля

Модульное программирование основано на понятии модуля - логически взаимосвязанной совокупности функциональных элементов, оформленных в виде отдельных программных модулей.

Модуль характеризуют:

  • один вход и один выход - на входе программный модуль получает определенный набор исходных данных, выполняет содержательную обработку и возвращает один набор результатных данных, т.е. реализуется стандартный принцип IPO (Input - Process - Output) - вход-процесс-выход;
  • функциональная завершенность - модуль выполняет перечень регламентированных операций для реализации каждой отдельной функции в полном составе, достаточных для завершения начатой обработки;
  • логическая независимость - результат работы программного модуля зависит только от исходных данных, но не зависит от работы других модулей;
  • слабые информационные связи с другими программными модулями - обмен информацией между модулями должен быть по возможности минимизирован;
  • обозримый по размеру и сложности программный элемент.

Таким образом, модули содержат определение доступных для обработки данных, операции обработки данных, схемы взаимосвязи с другими модулями.

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

Модульная структура программных продуктов

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

Однотипные функции реализуются одними и теми же модулями. Функция верхнего уровня обеспечивается главным модулем; он управляет выполнением нижестоящих функций, которым соответствуют подчиненные модули.

При определении набора модулей, реализующих функции конкретного алгоритма, необходимо учитывать следующее:

  • каждый модуль вызывается на выполнение вышестоящим модулем и, закончив работу, возвращает управление вызвавшему его модулю;
  • принятие основных решений в алгоритме выносится на максимально "высокий" по иерархии уровень;
  • для использования одной и той же функции в разных местах алгоритма создается один модуль, который вызывается на выполнение по мере необходимости. В результате дальнейшей детализации алгоритма создается функционально-модульная схема (ФМС) алгоритма приложения, которая является основой для программирования (рис. 18.3).

  

Рис. 18.3. Функционально-модульная структура приложения

Пример 18.5. Некоторые функции могут выполняться с помощью одного и того же программного модуля (например, функции Ф1 и Ф2).

  • Функция Ф3 реализуется в виде последовательности выполнения программных модулей.
  • Функция Фm реализуется с помощью иерархии связанных модулей.
  • Модуль n управляет выбором на выполнение подчиненных модулей.
  • Функция Фx реализуется одним программным модулем.

Состав и вид программных модулей, их назначение и характер использования в программе в значительной степени определяются инструментальными средствами. Например, применительно к средствам СУБД отдельными модулями могут быть:

  • экранные формы ввода и/или редактирования информации базы данных;
  • отчеты генератора отчетов;
  • макросы;
  • стандартные процедуры обработки информации;
  • меню, обеспечивающее выбор функции обработки и др.

Алгоритмы большой сложности обычно представляются с помощью схем двух видов:

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

Наиболее часто детально проработанные алгоритмы изображаются в виде блок-схем согласно требованиям структурного программирования; при их разработке используются условные обозначения согласно ГОСТ 19.003-80 ЕСПД (Единая система программной документации). Обозначения условные графические, ГОСТ 19.002-80 ЕСПД. Схемы алгоритмов и программ. Правила обозначения.

СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ

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

  

Рис. 18.4. Блок-схема алгоритма поиска в базе данных.

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

Пример 18.6. Алгоритм поиска в базе данных сведений о максимальном окладе сотрудников (рис. 18.4).

Таблица 18.1. Управляющие структуры алгоритмов

 

Типы управляющей структуры

Применение управляющей структуры

Последовательность

Блок 1

Блок 2

Конец

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

Для изменения порядка обработки блоков редактируется последовательность выполняемых

Альтернатива (условие выбора)

Начало

Да Условие Нет

Альтернатива1 Альтернатива2

Конец

В блоке Условие содержится условие выбора альтернативы обработки. Каждая альтернатива выполняется 1 раз; выполнение одной из двух альтернатив - обязательно.

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

Если ни одно из условий не выполнилось, происходит выход.

Цикл ("пока")

Начало

Условие

Нет Да

Тело цикла

Конец

В блоке Условие задается условие тела цикла - определенной обработки. Если условие не выполняется, цикл прерывается и осуществляется выход.

Условие может содержать счетчик повторений тела цикла либо логическое условие.

Тело цикла - произвольная последовательность блоков (операторов) обработки

ВВЕРХ

 


 

Скачано с www.znanio.ru

Архитектура компьютера. Физические основы функционирования компьютера

Архитектура компьютера. Физические основы функционирования компьютера

Отражение или рассеяние света от поверхности

Отражение или рассеяние света от поверхности

ЭВМ; опорную последовательность им­пульсов устройство управления получает от генератора тактовых импульсов; · арифметико-логическое устройство (АЛУ)—предназначено для вы­полнения всех арифметических и логических операций над числовой и…

ЭВМ; опорную последовательность им­пульсов устройство управления получает от генератора тактовых импульсов; · арифметико-логическое устройство (АЛУ)—предназначено для вы­полнения всех арифметических и логических операций над числовой и…

ВУ; обработку данных и их запись в

ВУ; обработку данных и их запись в

Основная память (ОП). Она предназначена для хранения и оперативного обмена ин­формацией с прочими блоками машины

Основная память (ОП). Она предназначена для хранения и оперативного обмена ин­формацией с прочими блоками машины

Модули DIMM имеют емкость 16, 32, 64, 128 или 256

Модули DIMM имеют емкость 16, 32, 64, 128 или 256

XMS (эту память называют тогда

XMS (эту память называют тогда

Ассемблер -- это не язык программирования

Ассемблер -- это не язык программирования

Регистры общего назначения (General

Регистры общего назначения (General

Замечание: Некоторые компиляторы, например yasm, позволяют в скобках писать 5*eax

Замечание: Некоторые компиляторы, например yasm, позволяют в скобках писать 5*eax

Практически все арифметически операции меняют флаги

Практически все арифметически операции меняют флаги

Best practice модуль числа test eax , eax jns

Best practice модуль числа test eax , eax jns

Циклы do-while do ... while (eax != 0 );

Циклы do-while do ... while (eax != 0 );

LE , L1 , LE , L2 , L2 , LE ,

LE , L1 , LE , L2 , L2 , LE ,

Где возвращается заначение? edx:eax/eax/ax ⬅️ ⬅️ ⬅️

Где возвращается заначение? edx:eax/eax/ax ⬅️ ⬅️ ⬅️

В stdcall не возможно написать printf, так как это vararg-функция

В stdcall не возможно написать printf, так как это vararg-функция

Обзор команд Загрузка fld (from float) fild (from integer) fbld (bcd80) fldpi / fld1 / fldz (load pi / 1 / 0 )

Обзор команд Загрузка fld (from float) fild (from integer) fbld (bcd80) fldpi / fld1 / fldz (load pi / 1 / 0 )

Calling convention Вызванная функция должна зачистить стек командой finit перед использованием x87

Calling convention Вызванная функция должна зачистить стек командой finit перед использованием x87

SSE2 (Pentium 4) : можно использовать xmm для int

SSE2 (Pentium 4) : можно использовать xmm для int

Compare packed signed Integer for greater than · pand/por/pxor/pandn - bitwise and/or/xor/and not · psrl{w, d, q} -

Compare packed signed Integer for greater than · pand/por/pxor/pandn - bitwise and/or/xor/and not · psrl{w, d, q} -

История про разгон кода TODO

История про разгон кода TODO

В некоторых командах есть свои умолчания

В некоторых командах есть свои умолчания

Дескриптор сегмента состоит из 8 байт и содержит все необходимую информацию о сегменте:

Дескриптор сегмента состоит из 8 байт и содержит все необходимую информацию о сегменте:

Тогда вызваемая функция может записать в

Тогда вызваемая функция может записать в

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

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

Замечание: AWE (Address Windowing

Замечание: AWE (Address Windowing

Первые 10 - индекс в page directory

Первые 10 - индекс в page directory

То есть в режиме copy-on-write

То есть в режиме copy-on-write

Чтобы увеличить виртуальное адресное пространство

Чтобы увеличить виртуальное адресное пространство

Есть системные библиотеки под каждую битность

Есть системные библиотеки под каждую битность

Изменения по сравнению с x86

Изменения по сравнению с x86

Замечание: Вместо xor rax, rax лучше писать xor eax, eax , так как занимает меньше места

Замечание: Вместо xor rax, rax лучше писать xor eax, eax , так как занимает меньше места

Замечание: сохранение xmm большая проблема

Замечание: сохранение xmm большая проблема

Это может быть полезно для последний функции

Это может быть полезно для последний функции

СТРУКТУРНОЕ ПРОЕКТИРОВАНИЕ И ПРОГРАММИРОВАНИЕ

СТРУКТУРНОЕ ПРОЕКТИРОВАНИЕ И ПРОГРАММИРОВАНИЕ

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

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

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

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

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

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

Например, применительно к средствам

Например, применительно к средствам

Рис. 18.4. Блок-схема алгоритма поиска в базе данных

Рис. 18.4. Блок-схема алгоритма поиска в базе данных

редактируется последовательность выполняемых

редактируется последовательность выполняемых

Цикл ("пока") Начало Условие

Цикл ("пока") Начало Условие
Материалы на данной страницы взяты из открытых истончиков либо размещены пользователем в соответствии с договором-офертой сайта. Вы можете сообщить о нарушении.
02.02.2023