0. INTRO.

Potemkin's Hackers Group (PHG)

 INFORMATION MUST BE FREE

(НО ЭТО НЕ ОТНОСИТЬСЯ К ПЕРСОНАЛЬНОЙ ИНФОРМАЦИИ)

 Computer Basics

 Основы компьютера для маньяков

    Copyright © PHG 1991..2009. All rights reserved.

    Computer Basics - начальный курс обучению комьютерной грамотности.
Разработан Алексеем Потемкиным.
Использовался для обучения в:
    o Доме Научно Технического Творчества Молодежи (ДНТТМ)

    o Лицее Информационных Технологий (ЛИТ)

    о в частном порядке

Настоящий текст является сильно чудовищно расширенной версией оригинального курса.

This is PHG's (Potemkin's Hackers Group) base study course for computer maniacs.

Contact information:

E-mail:	 chaos666x2@yahoo.ru
ICQ UIN: 20570214


0.0. ВНИМАНИЕ ПРОЧИТАЙТЕ ЭТУ СЕКЦИЮ

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

1) Русский язык просто конктретно хромает.

2) Во многих схемах вместо MOSFET полевых транзисторов нарисованны биполярные
   (иногда JFET). итд.
   В большинстве случаев это не влияет на принципиальную функциональность
   в краевых случаях, но существенно меняет электрические характеристики
   [В будующих версиях DOCа эти схемы будут перерисованны].

3) MISD - тема для отдельного обсуждения (как договорится о терминах,
   следует ли придерживатся классификации Флинна).

4) Очень много тем отсутствует или недостаточно детализированны.

ЧИТАТЕЛЬ, ПОМНИ, ЧТО ЭТО ЧЕРНОВИК, А НЕ ЗАКОНЧЕННАЯ ВЕРСИЯ.

В этом DOCе возможны ошибки как в схемах так и в программах итд.
Написание этого DOCа не является критически важной жизненной задачей для
автора, поэтому все как есть quick and dirty.
И скажите спасибо что это есть вообще.

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

Эта документация содержит 3rd party картинки.
Если правообладатель на картинку не согласен с ее использованием
то он должен об этом сообщить и картинка будет снята в следующей версии.
В любом случае использование автором чужих картинок - некоммерческое.


0.1. ЦЕЛИ

Основные цели, которые ставились при подготовке этого курса.

1) Показать откуда растут ноги у компьютера.

2) Показать взаимосвязи между уровнями (см. секцию 1)

3) Показать как и какая происходит оптимизация между уровнями

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

5) Расширить детям кругозор
   (Это касается как математической культуры, так и связи между вещами).

6) Немного помочь в решении извечной проблемы - "Хочу все знать"


1. УРОВНИ ПОНИМАНИЯ РАБОТЫ КОМПЬЮТЕРА

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

Level
7	Application Programs
6	OS
5	BIOS or Drivers                            SOFT
4	Hardware registers		------------------
3	Functional				   HARD
2	Logical		------------------------ RTL Transfers
1	Physical 	------- Topological      Gate
                Electrical       Transistors
                Technological

Давайте рассмотрим эти уровни кратко:

  Уровень 7 - Прикладные программы

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

  Уровень 6 - Операционные системы

Операционная система - это основная программа которая управляет ресурсами
компьютера (память, storage, процессорное время).
Операционная система предоставляет унифицированный интерфейс API с помощью которого
прикладные программы выполняют те или другие действия (например читают файл или
печатают на экране).

  Уровень 5 - BIOS или Drivers

Драйверы - программы которые осуществляют низкоуровневый доступ к конкретному оборудованию
(например к Ethernet контроллеру Realtek Rtl8139C). Драйверы предоставляют унифицированный
абстрагированный интерфейс для операционной системы. Поэтому OS может работать на
различном оборудовании - для разного оборудования разные драйверы осуществляют доступ
к конкретным устройствам.

  Уровень 4 - Регистры Hardware

Это уровень интерфейса между Software и Hardware. Именно так software заставляет hardware
делать необходимые действия. Например если мы на x86 PC компьютере запишем FEh в порт
ввода вывода с адрессом 64h, то установиться соответсующий hardware триггер и компьютер
получит сигнал об аппаратном сбросе (то же самое вы можете сделать если нажмете кнопку
RESET). Понятно что у разного hardware - разные регистры.

  Уровень 3 - Функциональный

Блоки составленные из логических элементов. Степень дробности может быть разной.
Например:  процессор, Ethernet controller, Timer, сумматор - это все компоненты
функционального уровня. Кстати про компоненты близкие к логическому уровню любят
говорить функционально-логические.

  Уровень 2 - Логический

Логические элементы.

  Уровень 1 - Физический

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

  Подуровни

Уровни  деляться на подуровни.

Например Уровень 6 (OS) можно разделить на следующие подуровни:
    - подуровень API для прикладных программ
    - подуровень собственно внутренней активности OS
    - подуровень интерфейсов для драйверов

  Уровни (продолжение)

Устоявшейся классификайии для уровней понимания работы компьютера нет.
Разные люди исползуют разные подходы в зависимости от своих целей.

Вот несколько таких примеров:

На рисунке немного другой взгляд на уровни в аспекте ISA (Instruction Set
Architecture) - набора комманд микропроцессора.

Что бы работать на конкретном семействе процессоров программы должны быть
скомпилированы под его ISA. Соответсвенно появляется компилятор.

Другой взгляд на Hardware уровни

Разделение на системный уровень и на уровень модулей.

Не стоит зацикливаться исключительно на Software уровнях.
Знание "железа" тоже очень важно для hackerа.

   Real Hacker = Soft Hacker + Hard Hacker.

Надо понимать как работает компьютер на любом уровне.
Понимание работы одного уровня дает знание двух соседних.
Знание соседнего уровня оптимизирует текущий.

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

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

В этом одно из основных отличиях в мировозрениях hackers (в хорошем смысле
этого слово, а не в опошленном желтой прессой) от корпоративной культуры

    OPTIMIZATION	vs  SPEED_OF_CREATION
    Hackers		    Microsoft

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

Если не испугались то - ВПЕРЕД!!


1.1. ЧИСЛА И ПРИСТАВКИ СИ

Чтобы заниматься оптимизацией надо уметь делать оценки. Не важно в попугаях или
в мартышках. Но эту оценку надо уметь высказать в числовом виде.
Для этого надо уметь считать
(не в смысле арифметики, а в смысле как у детей:
  - Я умею считать до 100!
  - A я до 1000!
  - Ну ты и крутой!)

Хороший инженер должен уметь быстро делать оценки. Хороший hacker должен быть
хорошим инженером. Поэтому займемся счетом.

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

  Числа

    10^100	гугол
        ...
    10^63   вигинтилион	  1000000000000000000000000000000000000000000000000000000000000000
    10^60	ундевигинтилион   1000000000000000000000000000000000000000000000000000000000000
    10^57	дуодевигинтилион  1000000000000000000000000000000000000000000000000000000000
    10^54	септдецелион	  1000000000000000000000000000000000000000000000000000000
    10^51	седецелион	  1000000000000000000000000000000000000000000000000000
    10^48	квиндецелион	  1000000000000000000000000000000000000000000000000
    10^45	кватуордецелион   1000000000000000000000000000000000000000000000
    10^42	тредецелион	  1000000000000000000000000000000000000000000
    10^39	додецилион	  1000000000000000000000000000000000000000
    10^36	ундецелион	  1000000000000000000000000000000000000
    10^33	децелеон	  1000000000000000000000000000000000
    10^30	нонилион	  1000000000000000000000000000000
    10^27	октилион	  1000000000000000000000000000
    10^24	септилион	  1000000000000000000000000
    10^21	секстилион	  1000000000000000000000
    10^18	квинтилион	  1000000000000000000
    10^15	квадрилион	  1000000000000000
    10^12	трилион		  1000000000000
    10^9	миллиард	  1000000000
    10^6	миллион           1000000
    10^3	тысяча            1000
    10^2*	сто               100
    10^1*	десять            10
    10^0	один		  1

Английский вариант (по языку, а не по стране) этой таблицы более интересный,
потому что имеет различия в Американском и Еропейском варианте.

    -------------------------------------------------------
    Num	US			EU      	SI
    -------------------------------------------------------
    10^3	thousand		thousand	kilo-
    10^6	millon			million		mega-
    10^9 	billion 		milliard 	giga-
    10^12 	trillion 		billion 	tera-
    10^15 	quadrillion 		billiard 	peta-
    10^18 	quintillion 		trillion 	exa-
    10^21 	sextillion 		trilliard 	zetta-
    10^24 	septillion 		quadrillion 	yotta-
    10^27 	octillion 		quadrilliard
    10^30 	nonillion 		quintillion
    10^33 	decillion 		quintilliard
    10^36 	undecillion 		sextillion
    10^39 	duodecillion 		sextilliard
    10^42 	tredecillion 		septillion
    10^45 	quattuordecillion 	septilliard
    -------------------------------------------------------

Если интересны дальнейшие имена для чисел, то можно прочитать секцию
    3.1. НЕПОЗИЦИОННЫЕ СИСТЕМЫ СЧИСТЛЕНИЯ
где даны имена для латинских числительных от которых они образуются.

Еще есть интересные имена для очень больших чисел.

Например googol (гугол) = 10^100 (десять в сотой степени - то есть это 1 с 100 нолей за ней)

Гугол больше чем количество атомов в известной нам части вселенной
(по разным подсчетам от 10^72 до 10^87).

И даже
googolplex = 10^googol = 10^(10^100)

  Приставки СИ

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

сравните

    двадцать миллионов байт
    двадцать мегабайт

что короче?

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

Компакность информации важна для нас.

Ниже приведены приставки СИ:

  --------------------------------------------------------------------
    Y	yotta	йотта	10^24		септилион
    Z	zetta	зетта	10^21		секстилион
    E	exa	экса    10^18		квинтилион
    P	peta	пета    10^15		квадрилион
    T	tera	тера    10^12		трилион
    G	giga	гига    10^9		миллиард
    M	mega	мега    10^6		миллион
    K	kilo	кило	10^3		тысяча
+			дека	10  		десять
  --------------------------------------------------------------------
-			деци	10^-1
            санти	10^-2
    m	milli	милли	10^-3
    u 	micro	микро	10^-6           иногда используют mk, но это не CИ.
    n	nano	нано	10^-9
    p	pico	пико	10^-12
    f	femto	фемто	10^-15
    a	atto	атто	10^-18
    z	septo	зепто	10^-21
    y	yocto	йокто	10^-24
  --------------------------------------------------------------------

Примеры:

1 ms = 1 msec = 1 * 10^-3 sec
1 us = 1 usec = 1 * 10^-6 sec = 1 mksec    случай когда имя и сокращенная нотация отличаются
1 ns = 1 nsec = 1 * 10^-9 sec

  Оценка информации

размер информации считается в битах и байтах.

на самом деле есть и другие варианты о них можно прочитать в секциях
    2.10. ТРОИЧНАЯ ЛОГИКА
    71.1. ТЕОРИЯ ИНФОРМАЦИИ

    бит - минимальная единица информация
          (может хранить либо 0, либо 1)

соответсвенно:

    полубайт = 4 бита
    байт     = 8 бит

    килобайт = 1000 байт.
    мегабайт = 1000 килобайт
    гигабайт = 1000 мегабайт
    терабайт = 1000 гигабайт
    эксабайт = 1000 терабайт

    KB - килобайт
    Kb - килобит
    MB - мегабайт
    Mb - мегабит

Чем отличается начинающий программист от законченного
Начинающий думает что в килобайте 1000 байтов
Законченный думает что в километре 1024 метра.

Приставки СИ с которыми Вы познакомились основаны на степени 10,
тем не менее сейчас есть приставки, которые ориентированы на степени 2,
только применяются они всегда только к количеству информации.

Единицы информации кратные степени 2:

    exbi	эксбибайт = 1024 пебибайт       2^60
    pebi	пебибайт  = 1024 тебибайт       2^50
    tebi	тебибайт  = 1024 гибибайт       2^40
    gibi	гибибайт  = 1024 мебибайт	2^30
    mebi	мебибайт  = 1024 кибибайт	2^20
    kibi	кибибайт  = 1024 байт		2^10

Например выражение 1 кибиметр - вызывает нездоровый ажиотаж у населения.

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

Из за этого пользователи удивляются - а почему у меня такой
маленький диск. (Сейчас эта нездоровая фигня перешла и на Flash)

    K		1 024   			+2%
    M		1 048 576                       +4%
    G		1 073 741 824                   +7%
    T		1 099 511 627 776               +10%
    P		1 125 899 906 842 624           +12%

И с увеличением на каждые 10^3 эта разница все растет.

В общем пользоваться числами и приставками очень весело.
Настоящие Hackers любят экзотику:

    аттопарсек
    наногод

Да и околокомпьютерная культура вносит свой вклад:

    1 гектар = 1024 метра
    1 метр   = 1024 киллограма

понятно что имеются в виду килобайты, мегабайты и гигабайты.

1.1.A
   Расчитать свой рост в аттопарсеках.

1.1.B
   Чему равны 5 наносекунд в пикогодах?

1.1.C
   Чему равен 1 терабайт в байтах, на сколько % это больше чем тебибайт?


1.2. ФИЗИЧЕСКИЕ ВЕЛИЧИНЫ И ИХ СВЯЗЬ ДРУГ С ДРУГОМ

  Физические величины

время:
    секунда

    секунда - интервал времени за который совершается 9192631770
    колебаний электромагнитного излучения,	соответствующим переходу между
    двумя сверхтонкими уровнями основного	состояния атома цезия изотопа 133
    в квантовом состоянии при температуре 0'K.

частота:
    частота = 1/время
    1 Гц = колебание в 1 секунду
    1 MHz = 10^6 (миллион) колебаний в секунду

длинна:

    метр
    1 метр - длинна которую проходит свет в вакууме за 1/299792458 секунды.

    длинна = время * скорость_света
    1 метр = (1 / 298000 Kм/сек) = 3.3 * 10^-9 сек = 3.3 mks

    1 GHz = 10^9 колебаний в секунду
    Сигнал проходит длинну 30 сантиметров. (реально меньше).

    Постоянная решетки кремния равна 5.43 ангстрема
    (1 ангстрем = 0.1 нанометр). т.е. постоянная решетки равна ~0.5 нм.

    При проектной норме 0.09 микрон элементу соответсвует квадрат
    со стороной (90 нм / 0.5 нм) = 180 шагов решетки. ~ 250 атомов.

количество вещества
    моль - содержит число Авогадро молекул
           (Na = 6.0221367 * 10^23)

    при нормальных условиях (температуре 0'C (273.2K), давлении 101,3 кПа)
    объем одного моля газа равен 22.4 литра.

    Земля содержит порядка 10^50 атомов

Заряд
    заряд электрона = -1.6021892 * 10^-19 Кл
    масса покоя электрона = 9.109554 * 10^-31 кг
    или в терминах энергии = 0.5110034 МэВ

    1 Кулон - количество электричества (заряд) проходящий через поперечное
    сечение проводника при силе тока 1 Ампер за время 1 секунду.

    1 Aмпер - сила постоянного тока который будучи пущенным по двум
    паралельным проводникам бесконечной длинны и незначительного сечения
    помещенными на растоянии 1 метр друг от друга в вакууме создавал
    между этими проводниками силу равную 2*10^-7 Ньютонов на метр длинны.

    1 Ньютон - равен силе сообщающей телу массой 1 кг ускорение 1 м/c^2
    в направлении действия силы.

    1 Вольт - электрическое напряжение вызывающее в цепи постоянный ток
    силой в 1 Ампер при мощности 1 Ватт.

    1 Ватт - мощность при которой за время 1 секунда совершается работа
    равная 1 Джоулю.

    1 Джоуль - работа совершаемая при перемещении точки приложения силы
    равной 1 Ньютон на растояние 1 метр в направлении действия силы.

масса:

    киллограмм - это масса международного эталона киллограма,
    хранящегося в Международном бюро мер и весов в городе Севр близ Парижа
    и представляющее собой цилиндр из 90% платины, 10% иридия.

    грамм = 10^-3 кг

----------------------------
- Что такое лошадиная сила?
- Это сила лошади ростом в 1 метр и весом в 1 килограмм!
- И где интерестно ты найдешь такую лошадь?
- Как где? В Париже, в палате мер и весов, под аргоновым колпаком!!!
----------------------------

температура:

    градус Кельвина = 1/273.16 термодинамической температуры тройной точки
    вещества Вода. Начало шкалы (0'K) соответсвует абсолютному нулю
    температуры.
    (При абсолютном нуле температуры энергия теплового движения молекул и
    атомов вещества равна нулю).

СИ определяет 7 основных единиц
    килограмм	(масса)
    метр		(длинна)
    секунда		(время)
    ампер		(сила тока)
    кельвин		(температура)
    моль		(количество вещества)
    кандела		(уровень освещенности)


2. БУЛЕВА АЛГЕБРА: ОПРЕДЕЛЕНИЯ

---------------------------------------------------
Эпиграф
    Как известно слабое отрицание сохраняет импликацию...
---------------------------------------------------

Булева Алгебра - алгебра логики.
Разработана Джоджем Булем (1815-1864) [George Boole]

  Определения

Def
===
    ЛОГИЧЕСКАЯ ПЕРЕМЕННАЯ
        бит (высказывание).
        может принимать значения
            0	ЛОЖЬ
            1	ИСТИНА

Def
===
    ЛОГИЧЕСКАЯ ФУНКЦИЯ
        F = f(x1,...xN)
            x1...xN - логические переменные

Def
===
    ВХОДНОЙ НАБОР
        определенная комбинация значений логических переменных
        в логической функции

    Максимальное число входных наборов 2 ** N, где N - число
    переменных.

    Пример входного набора
        F(x1,x2)
        x1 = 1, x2 = 0
        {1,0}  <- Входной набор

Def
===
    ТАБЛИЦА ИСТИННОСТИ
        представление логической функции в виде таблице
        в левой части которой записаны входные наборы
        а в правой соответствующие им значения логической
        функции.

    Пример таблицы истинности для функции NОT
        --------
        x  | NOT
        ---+----
        0  | 1
        1  | 0
        --------

Def
===
    ПОЛНОСТЬЮ ОПРЕДЕЛЕННАЯ ФУНКЦИЯ
        определена для всех входных наборов

Def
===
    ЧАСТИЧНО ОПРЕДЕЛЕННАЯ ФУНКЦИЯ
        определена для некоторых (не всех) входных наборов

    Что значит не определена для входного набора
    Значит нам ее значение при таком наборе безразлично
    Например такой входной набор никогда нам не подадут на устройство
    (Неопределенное значение обычно записывается как Х)
    Пример таблицы истинности для частично определенной функции
            --------
        x  |  F
        ---+----
        0  |  1
        1  |  X   <- Нам все равно какое значение функция примет при х=1
        --------

Def
===
    РАБОЧИЙ НАБОР
        входной набор который определен

Def
===
    БЕЗРАЗЛИЧНЫЙ НАБОР
        входной набор, который неопределен


2.1. ЛОГИЧЕСКИЕ ФУНКЦИИ

  Логические Функции одной переменной

F=F(x)

    X=0	X=1   |	F(X)   | Description
    --------------+--------+------------
    0	0     |	0      | тождественный 0
    0	1     | X      | повторение    X
    1	0     | X#     | отрицание     X  (инверсия)  NOT
    1	1     | 1      | тождественная 1

  Логические Функции двух переменных

F=F(X1,X2)

левая часть таблицы:
    заголовок - входные наборы
    данные    - значение функций для указанных входных наборов
-------------------------------------+---------------------------------------
X1 (A)	0	0	1	1    |
X2 (B)	0	1	0	1    |		Description
-------------------------------------+---------------------------------------
    0	0	0	0    |	0		тождественный 0
AND	0	0	0	1    |  X1 * X2		И
      0	0	1	0    |  X1 <- X2	запрет по X2
    0	0	1	1    |  X1		повторение X1
    0	1	0	0    |  X2 <- X1	запрет по X1
    0	1	0	1    |  X2		повторение X2
XOR	0	1	1	0    |  X1 (+) X2	ИСКЛЮЧАЮЩЕЕ ИЛИ
OR	0	1	1	1    |  X1 + X2		ИЛИ
NOR	1	0	0	0    |  (X1 + X2)#	ИЛИ-НЕ (стрелка Пирса)
EQV	1	0	0	1    |  X1 ~ X2		равнозначность
    1	0	1	0    |  X2#		отрицание X2
    1 	0	1	1    |  X2 -> X1 	импликация от X2
    1	1	0	0    |  X1#		отрицание X1
    1	1	0	1    |  X1 -> X2	импликация от X1
NAND	1	1	1	0    |  X1 / X2		И-НЕ (штрих Шеффера)
    1	1	1	1    |  1		тождественная 1
-------------------------------------+---------------------------------------


2.2. АЛГЕБРА ЛОГИКИ НА ПАЛЬЦАХ

  Диаграммы Венна

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

    И = истина	1
    Л = ложь        0

Операнды
    X1	A
    X2	B
    X3	C

Диаграмма Венна:
    Для каждого операнда - круг
    Круг делит все на 2 множества:
        внутри круга - операнд равен  1
        снаружи круга - операнд равен 0
    Круги пересекаются со всеми другими кругами
    Если значение функции в какой то зоне равно 1 то зона штрихуется,
    a если  0 то зона остается незакрашенной

Пример диаграммы Венна для двухоперандных функций:

Пример диаграммы Венна для трехоперандных функций:

  NOT (НЕ)

NOT (инверсия) - меняет значение операнда на противоположное.

    X   | НЕ X  			X | X#
    ----+-------                   ---+----
    Л   | И				0 | 1
    И   | Л                         1 | 0

Обозначения NOT:
        _
        X		X#

        ~X
                -+
        -+ X	        X

  AND (И)

                                               x2
        X2                            ------
    И |  Л   И			AND |  0  1  	карта Карно
    --+-----------                  ----+--------
   X1	Л |  Л   Л                     |  0 |  0  0
        И |  Л   И                  x1 |  1 |  0  1

                    A   B   |
    Л  и  Л  = Л			X1  X2  | AND	таблица истинности
    Л  и  И  = Л                   ---------+-----
    И  и  Л  = Л			0   0   | 0
    И  и  И  = И			0   1   | 0
                        1   0   | 0
                    1   1   | 1

Обозначения AND:
        A B
        A * B           	// логическое умножение
        A . B
        A & B			// язык С
        A and B
        A ^ B			// дезъюнкция

Операнды называются:

    конъюнкт  &  конъюнкт

  OR (ИЛИ)

                                               x2
                                     ------
    ИЛИ|  Л   И                     OR |  0  1
    ---+----------			---+--------
     Л |  Л   И                   |  0 |  0  1
     И |  И   И                 x1|  1 |  1  1

    A   B   |
    X1  X2	| OR
    --------+-----
    0   0	| 0
    0   1	| 1
    1   0	| 1
    1   1	| 1

Обозначения OR:
        A + B			// логическое сложение
        A | B			// язык С
        A V B			// конъюнкция
        A or B

Операнды называются:

    дезъюнкт V дезъюнкт

  EQV (РАВНОЗНАЧНОСТЬ)

Equivalence

                                                        x2
                                             -------
    EQV|  Л  И   				EQV | 0  1
    ---+---------           	        ----+-------
     Л |  И  Л              	       |  0 | 1  0
     И |  Л  И              	    x1 |  1 | 0  1

                        A   B   |
    экивалетна ли              		X1  X2	| EQV
        Ложь   Лжи 	= И		--------+-----
        Ложь   Истине   = Л 		0   0	| 1
        Истина Лжи      = Л		0   1	| 0
        Истина Истине   = И		1   0   | 0
                        1   1   | 1

    EQV(A,B) = (A and B)# or (A and B)

Обозначения EQV:
            A  ~  B		// алгебра Логики
        A equ B
        A eqv B
        A ==  B

  IMP (СЛЕДОВАНИЕ)

Implication (Следование)

Импликация (следование) из X1 -> X2
Несимметричная функция.

                                               x2
       X1->X2	x2                     X1->X2 ------
    IMP |  Л  И			IMP | 0  1
    ----+-------- 			----+-------
    x1	  Л |  И  И                    |  0 | 1  1
      И |  Л  И                  x1|  1 | 0  1

    A  B   |
    X1 X2  | IMP: X1->X2
        -------+-----
    0  0   |  1
    0  1   |  1
        1  0   |  0
        1  1   |  1

    Следует ли из
        Лжи Ложь      = И (Да)
        Лжи Истина    = И (Да) Из лжи может следовать что угодно
        Истины Ложь   = Л (Нет)
        Истины Истина = И (Да)

Поскольку нессиметричная, то есть и сопряженная:
импликация из X2 -> X1

Таблица истинности получается если поменять местами X1 и X2.

    B  A   |
    X2 X1  | IMP:  X2->X1
        -------+-----
    0  0   |  1
    0  1   |  1
        1  0   |  0
        1  1   |  1

приводим обратно:

    A  B   |
    X1 X2  | IMP:  X2->X1
        -------+-----
    0  0   |  1
    0  1   |  0
    1  0   |  1
    1  1   |  1

Обозначения импликации:
        A -> B		// импликация от А к B
        B -> A		// импликация от B к A

Операнды называются:

    антецедент ->   консеквент
    (посылка)	(заключение)

  NAND (И-НЕ)

NAND	И-НЕ		NAND(X,Y) = not (X and Y)

    NAND | 0  1
    -----+-------
       0 | 1  1
       1 | 1  0

    A  B  |
    X1 X2 | NAND
    ------+-----
    0  0  | 1
    0  1  | 1
    1  0  | 1
    1  1  | 0

Обозначения NAND:
        ___
        A B  		(AB)#
        _____
        A * B		(A * B)#
        _____
        A ^ B		(A ^ B)#
        _____
        A & B		(A & B)#
        _______
        A and B		(A and B)#

        A / B		Штрих Шеффера

Шеффер:

  NOR (ИЛИ-НЕ)

NOR	ИЛИ-НЕ		NOR(X,Y)  = not (X or  Y)

    NOR  | 0  1
    -----+-------
       0 | 1  0
       1 | 0  0

    A  B  |
    X1 X2 | NOR
    ------+-----
    0  0  | 1
        0  1  | 0
    1  0  | 0
    1  1  | 0

Обозначения NOR:
        _____
        A + B		(A + B)#
        _____
        A V B		(A V B)#
        ______
        A or B		(A or B)#

          |
        A V B		Стрелка Пирса

Пирс:

  XOR (ИСКЛЮЧАЮЩЕЕ ИЛИ)

    XOR (исключающее ИЛИ) - это сложение по модулю 2
    XOR(X,Y) = not (EQV(X,Y))
    XOR(X,Y) = (A# and B) or (B# and A)

    XOR  | 0  1
    -----+------
       0 | 0  1
       1 | 1  0

    A  B  |
    X1 X2 | XOR
    ------+-----
    0  0  | 0
    0  1  | 1
    1  0  | 1
    1  1  | 0

    заметим что кроме того x1 XOR x2 это  X1 != X2

Обозначение ХOR:
        A (+) B
        A xor B
        A <>  B
        A !=  B

  ЗАПРЕТ

Несимметричная функция

Запрет по Х2 (X1 <- X2):

Смысл в понятие теории множеств:
    вычитание X1 - X2
    т.е. подмножество элементы которого содержаться в X1,
         но не содержаться в X2.

Смысл:
    F  =  0, если X2 = 1
         X1, если X2 = 0

    X1 <- X2 = not(X1 -> X2)

    B  A  |
    X2 X1 | X1 <- X2
    ------+---------
    0  0  | 0
    0  1  | 1
    1  0  | 0
    1  1  | 0

приводим:

    A  B  |
    X1 X2 | X1 <- X2
    ------+---------
    0  0  | 0
    0  1  | 0
    1  0  | 1
    1  1  | 0

    собственно еще это можно выразить как X1 > X2

Сопряженная ей функция: запрет по Х1 (X2 <- X1)

    а эту можно выразить как X1 < X2

Обозначение запрета:
    X1 <- X2	запрет по X2
    X2 <- X1	запрет по X1

    X1 >  X2	запрет по X2
    X2 >  X1	запрет по X1
    X1 <  X2	запрет по X1
    X2 <  X1	запрет по X2

    X1 -  X2	запрет по X2
    X2 -  X1	запрет по X1

  Вырожденные случаи

Назовите функции соответствуещее случаям:

  Нульоперандные вырожденные

  Однооперандные вырожденные

  Примеры

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

  Трехоперандные функции

  AND3

    AND(A, B, C) = A * B * C = (A * B) * C = A * (B * C)

    B C A | AND
    ------+----
    0 0 0 | 0
    0 0 1 | 0
    0 1 0 | 0
    0 1 1 | 0
    1 0 0 | 0
    1 0 1 | 0
    1 1 0 | 0
    1 1 1 | 1

  OR3

    OR(A, B, C) = A + B + C = (A + B) + C = A + (B + C)

    B C A | OR
    ------+----
    0 0 0 | 0
    0 0 1 | 1
    0 1 0 | 1
    0 1 1 | 1
    1 0 0 | 1
    1 0 1 | 1
    1 1 0 | 1
    1 1 1 | 1

  NAND3

    NAND(A, B, C) = NOT(AND(A, B, C))

    B C A | NAND
    ------+----
    0 0 0 | 1
    0 0 1 | 1
    0 1 0 | 1
    0 1 1 | 1
    1 0 0 | 1
    1 0 1 | 1
    1 1 0 | 1
    1 1 1 | 0

  NOR3

    NOR(A, B, C) = NOT(OR(A, B, C))

    B C A | NOR
    ------+----
    0 0 0 | 1
    0 0 1 | 0
    0 1 0 | 0
    0 1 1 | 0
    1 0 0 | 0
    1 0 1 | 0
    1 1 0 | 0
    1 1 1 | 0

  XOR3

    XOR(A, B, C) = A (+) B (+) C = [A (+) B] (+) C = A (+) [B (+) C]

    B C A | XOR
    ------+----
    0 0 0 | 0
    0 0 1 | 1
    0 1 0 | 1
    0 1 1 | 0
    1 0 0 | 1
    1 0 1 | 0
    1 1 0 | 0
    1 1 1 | 1


2.3. АКСИОМЫ АЛГЕБРЫ ЛОГИКИ

Используем:
               _
    X# или X  = NOT   (инверсия)
    X + Y	  = OR    (конъюнкция)
    X * Y     = AND   (дизъюнкция)
    X (+) Y   = XOR   (исключающее ИЛИ)

Приоритеты операций:

    -------------------
    max    #       NOT
        ^      *       AND
        |      (+)     XOR
    min    +       OR
    -------------------

Например:

    A + B * C    	     значит    A + (B * C)
    A + B (+) C * D      значит    A + (B (+) (C * D))
    C#DE		     значит    (С#) * D * E

определение набора элементов:

    x = 0, если x != 1
    x = 1, если x != 0

определение операции дизъюнкции (OR):
    0 + 0 = 0
    1 + 1 = 1
    0 + 1 = 1 + 0 = 1

определение операции конъюнкции (AND):
    0 * 0 = 0
    0 * 1 = 1 * 0 = 0
    1 * 1 = 1

определение операции инверсии (NOT):
    _
    0 = 1
    _
    1 = 0


2.4. ЗАКОНЫ АЛГЕБРЫ ЛОГИКИ

Идемпотентные законы:
еще их называют законами повторения или тавтологии.

    X + X  = X
    X * X  = X

Комутативные (переместительные):

    X1 + X2	 = X2 + X1
    X1 * X2  = X2 * X1

Ассоциативные (сочетательные):

    X1 + X2 + X3 = X1 + (X2 + X3) = X2 + (X1 + X3) = X3 + (X1 + X2)
    X1 * X2 * X3 = X1 * (X2 * X3) = X2 * (X1 * X3) = X3 * (X1 * X2)

Дистрибутивные (распределительные):

    X1 * (X2 + X3)  =  X1 * X2  + X1 * X3  	конъюнкции относительно дизъюнкции
    X1 + X2 * X3	= (X1 + X2) * (X1 + X3) дизъюнкции относительно конъюнкции

Законы отрицания:

    0 + X  = X
    0 * X  = 0

    1 + X  = 1	законы универсального множества
    1 * X  = X

Законы дополнительности
    X + X# = 1	закон исключения третьего
    X * X# = 0	закон логического противоречия

Закон двойного отрицания:
        _____
          _     =
    ( X ) = X = X

Законы Де-Моргана (Законы двойственности):

    _______   __   __
    X1 + X2 = X1 * X2

        _______   __   __
    X1 * X2 = X1 + X2

    в общей форме для N переменных
    (X1 + X2 + ... + XN)#  = X1# * X2# * ... * XN#
    (X1 * X2 + ... + XN)#  = X1# + X2# + ... + XN#

Законы поглощения (адсорбции):

    X + X * Y    = X
    X * (X + Y)  = X

Законы склеивания (распространения):
              _
    XY + XY = X
            _
    (X+Y)(X+Y) = X

Законы обобщенного склеивания:

         _              _
    XY + XZ + YZ = XY + XZ
          _                   _
    (X+Y)(X+Z)(Y+Z) = (X + Y)(X + Z)

            _
    X + XY = X + Y
      _
    X(X + Y) = XY

Законы связанные с XOR

собственно определение XOR:
               _     _
    X (+) Y  = XY + XY  (по определению)

откуда:
    X (+) 0  = X
    X (+) 1  = X#
    X (+) X  = 0
    X (+) X# = 1

Комутативный:

    X (+) Y = Y (+) X

Ассоциативный:

    X (+) [Y (+) Z] = [X (+) Y] (+) Z

Дистрибутивный:
    X *   [Y (+) Z] = (X * Y) (+) (X * Z)

Следствия:

        _______   _ _         _               _
    X (+) Y = X*Y + X*Y = X (+) Y = X (+) Y

                _
    X (+) XY = XY
    _     _    _   _
    X (+) XY = X * Y

    _          _
    X (+) XY = X + Y

                    _
    X (+) (X + Y) = XY
    _      _
    X (+) (X + Y) = XY
           _        _   _
    X (+) (X + Y) = X + Y

                _    _
    XY (+) (X + Y) = Y
            _        _
        XY (+) (X + Y) = X
        _       _                     _               _
    XY (+) XY = XY (+) (X + Y) = (X + Y) (+) (X + Y) = X (+) Y

    _           _    ______          _
    XY (+) (X + Y) = X + Y# (+) (X + Y) = 1

Законы связанные с импликацией:

Закон контрапозиции:
                 _    _
    A -> B = B -> A

         ______
    A -> B = A <- B

             _
    A -> B = A + B

    A ~ B = (A -> B) * (B -> A)

Все законы могут быть доказаны аналитически или перебором.

Пример доказательства аналитически:
              _
    XY + XY = X
             _
    X * (Y + Y) = X		[ A*(B+C) = AB + AC ]
                                  _
    X * 1 = X,  		[ X + X = 1]

    X = X		тождество чтд

Пример доказательства перебором:

Надо доказать:
    X1 + X1 * X2 = X1

X1 может быть либо 0, либо 1.

Пусть X1=0, тогда
    0  + 0 * X2 = 0
    0  +   0    = 0
    0           = 0		тождество

Теперь пусть X1=1, тогда
    1 + 1 * X2  = 1
    1 + A       = 1
    1           = 1		тождество

Что и требовалось доказать.

Можно также доказывать теоретико-множественным методом:


2.5. НОРМАЛЬНАЯ ФОРМА ЛОГИЧЕСКОЙ ФУНКЦИИ

Def
===
    ЭЛЕМЕНТАРНАЯ КОНЪЮНКЦИЯ
        логическое произведение переменных функции,
        при зтом каждая переменная может входить либо
        в неизмененном виде, либо в виде инверсии
        (каждая переменная может входить только один раз)

    Пример:
        F(x1,x2,x3,x4)

            x1*x2*x3*x4
            x1*x2#*x3*x4
            x1*x2#*x3#*x4
            x1#*x2#*x3#*x4#

Каждой элементарной конъюнкции соответствует свой входной набор,
на котором ее значение превращается в 1 (на всех остальных оно равно 0)

        --------------------------------------
                                        Входной набор
        Эл.Конъюнкция		x1 x2 x3 x4
        --------------------------------------
        x1*x2*x3*x4		1  1  1  1
        x1*x2#*x3*x4            1  0  1  1
        x1*x2#*x3#*x4           1  0  0  1
        x1#*x2#*x3#*x4#		0  0  0  0
        --------------------------------------

Элементарные конъюнкции для двухоперандной функции:

Элементарные конъюнкции для трехоперандной функции:

Def
===
    ЭЛЕМЕНТАРНАЯ ДИЗЪЮНКЦИЯ
        логическое сумма  переменных функции,
        при зтом каждая переменная может входить либо
        в неизмененном виде, либо в виде инверсии
        (каждая переменная может входить только один раз)

    Пример:
        F(x1,x2,x3,x4)

            x1+x2+x3+x4
            x1#+x2+x3+x4#
            x1#+x2#+x3#+x4#

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

        --------------------------------------
                                        Входной набор
        Эл.Дизъюнкция		x1 x2 x3 x4
        --------------------------------------
        x1+x2+x3+x4		0  0  0  0
        x1#+x2+x3+x4#           1  0  0  1
        x1#+x2#+x3#+x4#         1  1  1  1
        --------------------------------------

Def
===
    РАНГ ЭЛЕМЕНТАРНОЙ КОНЪЮНКЦИИ/ДИЗЪЮНКЦИИ
        равен количеству переменных в ней

Def
===
    СОСЕДНИЕ ЭЛЕМЕНТАРНЫЕ КОНЪЮНКЦИИ/ДИЗЪЮНКЦИИ
        две злементарные конъюнкции/дизъюнкции одного ранга
        которые отличаются только инверсией одной из переменных

    На диаграмме Венна такие области имеют общую границу
    На карте Карно (до 4x4) - это соседние клетки.

Def
===
    НОРМАЛЬНАЯ ФОРМА ФУНКЦИИ
        это представление функции в виде суммы элементарных
        конъюнкций (ранга равного числу переменных функции)
        это конъюнктивная нормальная форма
        (элементарную конъюнкцию в ней называют МИНИТЕРМ)

        или представление функции в виде произведения элементарных
        дизъюнкций (ранга равного числу переменных функции)
        это дизъюнктивная нормальная форма
        (элементарную дизъюнкцию в ней называют МАКСИТЕРМ)

Общий вид нормальной формы:

    F1(x) 	   = c0*x + c1*x#
    F2(x1,x2)  = c0*x1*x2 + c1*x1*x2# + c2*x1#*x2 + c3*x1#*x2#

    F2(x1,x2)  = (c0 + x1  + x2) * (c1 + x1  + x2#) *
             (c2 + x1# + x2) * (c3 + x1# + x2#)

    Для конкретной функции все коэффициенты 'c' равны 0 или 1
    Пример:
       Конъюнктивная форма:
        AND(x1,x2) = 1*x1*x2 + 0*x1#*x2 + 0*x1*x2# + 0*x1#*x2#
               = x1*x2

            --------------------------------------------------------
            args   |       	        минтермы               |   +
            x2 x1  |c0*x1*x2|c1*x1#*x2|c2*x1*x2#|c3*x1#*x2#| Result
            -------+--------+---------+---------+----------+--------
            0  0   |   0	   (0)        (0)	(0)    |   0
            0  1   |   0       (0)        (0)       (0)    |   0
            1  0   |   0       (0)        (0)       (0)    |   0
            1  1   |   1       (0)        (0)       (0)    |   1
            --------------------------------------------------------

        OR (x1,x2) = 1*x1*x2 + 1*x1*x2# + 1*x1#*x2 + 0*x1#*x2#
               = x1*x2 + x1*x2# + x1#*x2

            --------------------------------------------------------
            args   |       	        минтермы               |   +
            x2 x1  |c0*x1*x2|c1*x1#*x2|c2*x1*x2#|c3*x1#*x2#| Result
            -------+--------+---------+---------+----------+--------
            0  0   |   0	     0        0         (0)    |   0
            0  1   |   0         0        1         (0)    |   1
            1  0   |   0         1        0         (0)    |   1
            1  1   |   1         0        0         (0)    |   1
            --------------------------------------------------------

        XOR (x1,x2) = 0*x1*x2 + 1*x1#*x2 + 1*x1*x2# + 0*x1#*X2#
                = x1#*x2 + x1*x2#

            --------------------------------------------------------
            args   |       	        минтермы               |   +
            x2 x1  |c0*x1*x2|c1*x1#*x2|c2*x1*x2#|c3*x1#*x2#| Result
            -------+--------+---------+---------+----------+--------
            0  0   |  (0)	     0        0         (0)    |   0
            0  1   |  (0)        0        1         (0)    |   1
            1  0   |  (0)        1        0         (0)    |   1
            1  1   |  (0)        0        0         (0)    |   0
            --------------------------------------------------------

       Дизъюнктивная форма:
        OR (x1,x2) = (x1 + x2) * (1 + x1  + x2#) * (1 + x1# + x2) *
                     (1 + x1# + x2#)
               = (x1 + x2)

            --------------------------------------------------------
            args   |       	        мaкстермы              |   *
            x2 x1  |c0+x1+x2|c1+x1#+x2|c2+x1+x2#|c3+x1#+x2#| Result
            -------+--------+---------+---------+----------+--------
            0  0   |   0	   (1)        (1)      (1)     |   0
            0  1   |   1       (1)        (1)      (1)     |   1
            1  0   |   1       (1)        (1)      (1)     |   1
            1  1   |   1       (1)        (1)      (1)     |   1
            --------------------------------------------------------

        AND(x1,x2) = (0 + x1 + x2)  * (0 + x1 + x2#) *
                 (0 + x1# + x2) * (1 + x1# + x2#)
               = (x1 + x2) * (x1 + x2#) * (x1# + x2)

            --------------------------------------------------------
            args   |       	        мaкстермы              |   *
            x2 x1  |c0+x1+x2|c1+x1#+x2|c2+x1+x2#|c3+x1#+x2#| Result
            -------+--------+---------+---------+----------+--------
            0  0   |   0	    1	      1		(1)    |   0
            0  1   |   1        0         1         (1)    |   0
            1  0   |   1        1         0         (1)    |   0
            1  1   |   1        1         1         (1)    |   1
            --------------------------------------------------------

        XOR(x1,x2) = (0 + x1 + x2)  * (1 + x1# + x2) *
                 (1 + x1 + x2#) * (0 + x1# + x2#)
               = (x1 + x2)*(x1# + x2#)

            --------------------------------------------------------
            args   |       	        мaкстермы              |   *
            x2 x1  |c0+x1+x2|c1+x1#+x2|c2+x1+x2#|c3+x1#+x2#| Result
            -------+--------+---------+---------+----------+--------
            0  0   |   0	   (1)	     (1)	 1     |   0
            0  1   |   1       (1)       (1)         1     |   1
            1  0   |   1       (1)       (1)         1     |   1
            1  1   |   1       (1)       (1)         0     |   0
            --------------------------------------------------------

    Логическую сумму двух соседних элементарных коньюнкций ранга R
    можно заменить на элементарную конъюнкцию ранга R-1
    выбросив переменную, инверсия которой различается:

    Основание:
        A * B * C + A * B * C# = A * B * (C + C#) = A * B
                         +------+
                           = 1

                    x1	      x1#
    Пример:              -----            ------
        OR (x1,x2) = x1*x2 + x1*x2# + x1#*x2
                 -----   ------
                x2      x2#

        OR (x1,x2) = x2 + x1*x2#
        OR (x1,x2) = x1 + x1#*x2

Здесь приведены все минтермы для функции 3х переменных:

Здесь приведены все макстермы для функции 3х переменных:


2.5.1. БУЛЕВСКИЙ ДИФФЕРЕНЦИАЛ

d/dXi F(X1,...,Xi,...Xn) = F(X1,...,X{i-1},0,X{i+1},..,Xn) (+)
                           F(X1,...,X{i-1},1,X{i+1},..,Xn)

Дифференциал показывает насколько изменится значение функции если мы изменим
одну конкретную переменную в этой функции.

Пример:

    d/dX1 AND(x1, x2) = AND(0, X2) (+) AND (1, X2) =
              =       0    (+)      X2     =
              =       X2

  таким образом если мы изменим X1 то значение функции измениться на X2
  т.е. если X2 = 1, то значение функции изменится при изменении X1,
    a  если X2 = 0, то значение функции не изменится при изменении x1.

Нормальная форма для XOR:

  F(X1,X2,..Xn) = F(0,0,...,0) * (1(+)X1)*...*(1(+)Xn)      (+)
                  F(1,0,...,0) * X1 * (1(+)X1)*...*(1(+)Xn) (+)
                   ...
                  F(1,1,...,1) * X1 * X2 * ... Xn

Напишем нормальную XOR форму для AND:

    AND(x1,x2) = AND(0,0) * (1(+)x1)*(1(+)x2) (+)
                     AND(1,0) *  X1     *(1(+)x2) (+)
                     AND(0,1) * (1(+)X2)*   x2    (+)
                     AND(1,1) *  X1     *   x2
           =    0     *   X1#   *   x2#   (+)
                        0     *   X1    *   x2#   (+)
                        0     *   X2#   *   x2    (+)
                        1     *   X1    *   x2
           =    0   (+)  0 (+) 0 (+)  1 * X1 * X2
           =   X1 * X2

    OR(X1, X2) = OR(0,0) * (1(+)x1)*(1(+)X2)  (+)
             OR(1,0) *   X1    *(1(+)X2)  (+)
             OR(0,1) * (1(+)X1)*  X2      (+)
                     OR(1,1) *   X1    *  X2
           =    0    *   X1#   *  X2#     (+)
           =    1    *   X1    *  X2#     (+)
                   =    1    *   X1#   *  X2      (+)
                   =    1    *   X1    *  X2
           =   0 (+)  X1#*X2# (+) X1*X2# (+) X1*X2
           =   X1#*X2# (+) X1*X2# (+) X1*X2

--------------------------------------------------------
args   |       	        XORтермы               |
       | F(0,0)* | F(1,0)* | F(0,1)* | F(1,1)* |
       |(1(+)x1)*|  x1*    |(1(+)x1)*|   x1*   |  (+)
x2 x1  |(1(+)x2) |(1(+)X2) |   x2    |   x2    | Result
-------+---------+---------+---------+---------+--------
0  0   |   (0)	     0	       0	  0    |   0
0  1   |   (0)       1         0          0    |   1
1  0   |   (0)       0         1          0    |   1
1  1   |   (0)       0         0          1    |   1
-------------------------------------------------------

Очень похоже на коньюнктивную форму (собственно это она и есть), потому что тоже
минтермы, (для каждого входного набора есть только один минтерм который на
данном наборе равен 1, все остальнве равны 0), а случаях 0(+)0 и 0(+)1 -
все равно что использовать: XOR или OR


2.6. КАРТЫ КАРНО

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

Придумал Морис Карно (Maurice Karnaugh) в 1950 (Bell Labs)

Примеры шаблонов карт Карно (для разного числа переменных):

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

  Пример заполнения (2 переменных)

Собственно сам шаблон карты:

            x2
     -------
          0   1
    +---+---+
    | 0 |   |   |
  x1|   +---+---+
    | 1 |   |   |
        +---+---+

Предположим мы хотим сделать карту для функции AND.
Берем таблицу истинности:

    x2 x1  | AND
    -------+-----
    0  0   | 0
    0  1   | 0
    1  0   | 0
    1  1   | 1

Вносим значения функции в клетки соответствующие входным наборам:

x2=0, x1=0 => 0

            x2
     -------
          0   1
    +---+---+
    | 0 | 0 |   |
  x1|   +---+---+
    | 1 |   |   |
        +---+---+

x2=0, x1=1 => 0

            x2
     -------
          0   1
    +---+---+
    | 0 | 0 |   |
  x1|   +---+---+
    | 1 | 0 |   |
        +---+---+

x2=1, x1=0 => 0

            x2
     -------
          0   1
    +---+---+
    | 0 | 0 | 0 |
  x1|   +---+---+
    | 1 | 0 |   |
        +---+---+

x2=1, x1=1 => 1
            x2
     -------
          0   1
    +---+---+
    | 0 | 0 | 0 |
  x1|   +---+---+
    | 1 | 0 | 1 |
        +---+---+

Все карта построенна.

  Пример заполнения (3 переменных)

Попробуем теперь построить карту с 3 переменными.
Возьмем для этого функцию XOR.

Шаблон карты:

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	|   |   |   |   |
    x1  +---+---+---+---+
      1 |   |   |   |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

Берем таблицу истинности:

    x3 x2 x1 | XOR
    ---------+-----
    0  0  0  | 0
    0  0  1  | 1
        0  1  0  | 1
        0  1  1  | 0
        1  0  0  | 1
    1  0  1  | 0
    1  1  0  | 0
    1  1  1  | 1

Заполняем:
(0,0,0) => 0

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	|   | 0 |   |   |
    x1  +---+---+---+---+
      1 |   |   |   |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

(0,0,1) => 1

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	|   | 0 |   |   |
    x1  +---+---+---+---+
      1 |   | 1 |   |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

(0,1,0) => 1

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	|   | 0 | 1 |   |
    x1  +---+---+---+---+
      1 |   | 1 |   |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

(0,1,1) => 0

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	|   | 0 | 1 |   |
    x1  +---+---+---+---+
      1 |   | 1 | 0 |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

(1,0,0) => 1

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	| 1 | 0 | 1 |   |
    x1  +---+---+---+---+
      1 |   | 1 | 0 |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

(1,0,1) => 0

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	| 1 | 0 | 1 |   |
    x1  +---+---+---+---+
      1 | 0 | 1 | 0 |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

(1,1,0) => 0

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	| 1 | 0 | 1 | 0 |
    x1  +---+---+---+---+
      1 | 0 | 1 | 0 |   |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

и наконец (1,1,1) => 1

            0  x2   1
     ------- -------
    +---+---+---+---+
      0	| 1 | 0 | 1 | 0 |
    x1  +---+---+---+---+
      1 | 0 | 1 | 0 | 1 |
    +---+---+---+---+
     --- ------- ---
          1     0     1  x3

Карта готова

  Минтермы на Картах Карно

Пример минтермов на карте Карно:

Примеры:

       X2	                          X2 X3
      0  1                          00 01 11 10     <---------------+
        +------+		      +-------------+	                |
X1    0	| 1  0 |                X1  0 |  0  0  1  0 |                   |
      1	| 0  0 |                    1 |  1  1  0  0 |                   |
        +------+                      +-------------+                   |
                                                               --+  |
Обратите внимание что значения в строке/столбце меняются так, чтобы  |--+
изменялся один бит.                                                  |
                                                                   --+

    При числе переменных > 6, карты Карно становятся слишком
сложными для практического применения.

  Оптимизация с помощью карт Карно

С помощью карт карно очень удобно выделять элементарные конъюнкции

             X3X4
          00 01 11 10
        +-------------+
      00|	      |		ячейка Z [X1,X2,X3,X4] = [0,1,1,1]
X1X2  01|       Z     |		Если она равна 1 то ей соответствует
      11|	      |		элементарная конъюнкция  где
      10|             |		если Xi == 1, то Xi
        +-------------+		ecли Xi == 0, то Xi#
                                т.e. для Z элементарная конъюнкция равна
                    X1#*X2*X3*X4

Таким образом можно по карте Карно легко написать нормальную форму:

             X3X4
          00 01 11 10
        +-------------+
      00| 1  0  0  0  |		F(X1,X2,X3,X4) = X1#*X2#*X3#*X4# +
X1X2  01| 0  1  0  1  |                          X1#*X2*X3#*X4   +
      11| 0  0  0  1  |                          X1#*X2*X3*X4#   +
      10| 0  0  0  0  |                          X1*X2*X3*X4#
        +-------------+

Карта Карно помогает нам увидеть места где мы можем сократить ранг
элементарной конъюнкции (мв просто увидим соседние клетки):

             X3X4
          00 01 11 10
        +-------------+
      00|	      |
X1X2  01|       1  1  |		X1,X2,X3 у обоих клеток одинаковы
      11|	      |		X4 меняется - его можно выкинуть
      10|             |		Результат:  X1#*X2*X3 описывает обе клетки
        +-------------+

             X3X4
          00 01 11 10
        +-------------+
      00|	      |
X1X2  01|    1  1     |		X2 и X4 одинаковы, X1 и X3 меняются
      11|    1	1     |		Результат:  X2*X4
      10|             |
        +-------------+

На самом деле карта Карно является зацикленной с обоих сторон
(поэтому этот случай такой же кфк и предидущий):

         +--------------+
                 |              |
                 V              |
             X3X4               |
          00 01 11 10           |
        +-------------+         |    	X4 и X2 одинаковы, X1 и X3 меняются
      00| 1	    1 |		|	Результат:  X2#*X4#
X1X2  01|             |         |
 +--> 11|	      |<----+   |
 |    10| 1         1 |     |   |
 |      +-------------+     |   |
 |             ^            |   |
 |             |            |   |
 |             +------------|---+
 |			    |
 +--------------------------+

             X3X4
          00 01 11 10
        +-------------+
      00|	1     |			X3 и X4 одинаковы, X1 и X2 меняются
X1X2  01|       1     |			результат:  X3*X4
      11|	1     |
      10|       1     |
        +-------------+

             X3X4
          00 01 11 10
        +-------------+			X1 и X2 одинаковы, X3 и X4 меняются
      00|	      |			результат: X1#*X2
X1X2  01| 1  1  1  1  |
      11|	      |
      10|             |
        +-------------+

             X3X4
          00 01 11 10
        +-------------+
      00| 1  1  1  1  |			X1 одинаковый, X2/X3/X4 меняются
X1X2  01| 1  1  1  1  |			результат:  X1#
      11|	      |
      10|             |
        +-------------+

             X3X4
          00 01 11 10
        +-------------+
      00|    1  1     |			X4 одинаковый, X1/X2/X3 меняются
X1X2  01|    1  1     |			результат: X4
      11|    1	1     |
      10|    1  1     |
        +-------------+

Пример термов на карте карно

Связь карты карто и гиперкуба состояний:

Минтермы соответствующего ранга - это вершины, ребра, грани, гиперграни гиперкуба.

  Оптимизация смежных конъюнкций

Общая задача оптимизации - уменьшить число элементарных операций
для вычисления.

             X3X4
          00 01 11 10
        +-------------+
      00|             |		Видим терм для оптимизации:
X1X2  01|   (1  1)    |         (X1,X2,X4 - одинаковые) => X1#*X2*X4
      11|	1     | 	и отдельно [1111]	=> X1*X2*X3*X4
      10|             |
        +-------------+

т.e. функция F(x1,x2,x3,x4) = X1#*X2*X4 + X1*X2*X3*X4
    (одно сложение, 5 умножений),
но:

             X3X4
          00 01 11 10
        +-------------+
      00|	^     |
X1X2  01|    1  1     |		Можем описать вертикальный терм
      11|	1     |		(X2,X3,X4 - одинаковые => X2*X3*X4
      10|       V     |
        +-------------+

Поскольку 1 + 1 = 1, мы можем представить нашу функцию в виде перекрывания
термов:
          F(x1,x2,x3,x4) = X1#*X2*X4 + X2*X3*X4
      (одно сложение, 4 умножения)

  Оптимизация при безразличных наборах

Если у нас есть безразличные наборы мы можем трактовать их и как 0
и как 1 минимизируя функцию:

             X3X4
          00 01 11 10                             00 01 11 10
        +-------------+                         +-------------+
      00|    X  1  1  |		              00|    0  1  1  |
X1X2  01|    X  1  X  |   трактуем как	      01|    0  1  1  |
      11|	1  X  |                       11|       1  1  |
      10|             |                       10|             |
        +-------------+                         +-------------+

Получаем 2 четверки:
    X1 и X3  постоянны     X1#*X3
    X2 и X3  постоянны     X2*X3

таким образом:  F(x1,x2,x3,x4) = X1#*X3 + X2*X3  	// 3 действия
дальнейшая оптимизация	       = X3 * (X1# + X2)	// 2 действия

  Карты карно для большого числа переменных

Карты карно для 5 переменных:

Как комбинация карт для 4х переменных

         X5=0	    X5=1
             X3X4            X3X4
          00 01 11 10     00 01 11 10
        +-------------+ +-------------+
      00|    1        |	|    1        |		X1,X3,X4 - постоянны
X1X2  01|    1        | |    1        |         X2,X5    - меняются
      11|	      | |             |         Результат: X1#*X3#*X4
      10|             | |             |
        +-------------+ +-------------+

Карты Карно для 6 переменных

         X5=0	    X5=1
             X3X4            X3X4
          00 01 11 10     00 01 11 10
        +-------------+ +-------------+
      00| 1           |	|             |
X1X2  01|             | |             |   X6=0
      11|	      | |             |         X1,X2,X3,X4,X6 -постоянны
      10|             | |             |		X6 - меняются
        +-------------+ +-------------+         Результат:
        +-------------+ +-------------+         X1#*X2#*X3#*X4#*X5#
      00| 1           |	|             |   X6=1
X1X2  01|             | |             |
      11|	      | |             |
      10|             | |             |
        +-------------+ +-------------+

  Использование карт карно для макситермов

           X2
      0  1
    +------+
      0	| 0  1 |
X1    1 | 1  0 |
    +------+

    F =  X1*X2# + X1#*X2
           10	01

смотрим не единицы а нули:

    F =  (X1 + X2) * (X1# + X2#)
        00	      11

       ----------------------------
       X1 X2   X1+X2	X1#+X2#	F
       ----------------------------
    00	0   	  1	0
    01      1         1     1
    10      1         1     1
    11      1         0     0
       ----------------------------

Вообще говоря при минимизации смотрят, что занимает меньшее количество
элементов (дизъюнктивная или конъюнктивная форма) и выбирают ее.

             X3X4
          00 01 11 10
        +-------------+
      00| 1  1	1  1  |			X3 и X4 одинаковы, X1 и X2 меняются
X1X2  01| 1  0  1  1  |			результат:  X3*X4
      11| 1  1	1  1  |
      10| 1  1  1  0  |
        +-------------+

    F = (X1 + X2# + X3 + X4#) * (X1# + X2 + X3# + X4)

ясно что это меньше чем коньюктивная форма

  Оптимизация единичных 0 внутри блоков 1ц.

             X3X4
          00 01 11 10
        +-------------+
      00| 0  0	1  1  |		0 в блоке:
X1X2  01| 0  0  1  1  |		       	X1 = 1, X2 = 1, X4 = 1
      11| 0  0	0  1  |
      10| 0  0  1  1  |
        +-------------+

Рассмотрим полный блок:

             X3X4
          00 01 11 10
        +-------------+
      00| 0  0	1  1  |
X1X2  01| 0  0  1  1  |		Полный блок X3
      11| 0  0	1  1  |
      10| 0  0  1  1  |
        +-------------+

Результат для блока с нулем:

                X3 * (X1 * X2 * X4)#

                везде где X3 = 1,
                и где (X1,X2,X3) != (1,1,1)

             X3X4
          00 01 11 10
        +-------------+
      00| 0  0	1  1  |		0 в блоке:
X1X2  01| 0  0  1  0  |		       	X1 = 0, X2 = 1, X4 = 0
      11| 0  0	1  1  |
      10| 0  0  1  1  |
        +-------------+

Результат для блока с нулем:	X3 * (X1# * X2 * X4#)#

  A что если XOR?

             X3X4
          00 01 11 10
        +-------------+
      00| 0  1	0  1  |
X1X2  01| 1  0  1  0  |	   XOR(x1,x2,x3,x4)
      11| 0  1	0  1  |
      10| 1  0  1  0  |
        +-------------+

             X3X4
          00 01 11 10
        +-------------+
      00| 1  0	1  0  |
X1X2  01| 0  1  0  1  |	   NOT(XOR(x1,x2,x3,x4))
      11| 1  0	1  0  |
      10| 0  1  0  1  |
        +-------------+

             X3X4
          00 01 11 10
        +-------------+
      00| 1  0	1  0  |
X1X2  01| 0  1  0  1  |	   тоже не подарок
      11| 1  0	1  1  |
      10| 0  1  1  1  |
        +-------------+

Собственно плохо оптимизируется как минтермами так и макстермами
Умение распозновать и использовать XOR - это исскуство :)


2.6.1. ОПТИМИЗАЦИЯ МЕТОДОМ КУИНА-МАККЛАСКИ

Вообще то говоря Квайна (Quine), но в старой рускоязычной литературе - Куина.

Карты Карно хороши, когда число входов мало. (меньше или равно 5).
Что же делать если число входов велико?

Существуют методы
Основной из них - метод Куина-Маккласки (Quine-McCluskey):

Метод базируется на соотношеии:
    X*Y + X#*Y = Y

1) Берем таблицу истинности выписываем бинарно все минтермы (элементарные
   конъюнкции рангом равным рангу функции).

2) Затем ищем минтермы которые отличаются на один бит, и вносим их в таблицу
   минтермов более высокого уровня, так продолжаем пока не закончатся минтермы.

3) Затем процессируем термы большего порядка (см пункт (2)).
   До тех пор пока минтермов большего порядка не будет.

4) Выписываем минтермы начиная с меньшего ранга, при этом связанные минтермы
   в таблицах большего ранга не выписываем.

  Пример

Не факт что досчитан до конца, главное показана идея.

Таблица истинности функции:
    -------------------------------------------------------------
    X1X2X3X4 F(X)	Term		Пары различающиеся на 1 бит
    -------------------------------------------------------------
    0000	  1	X1#X2#X3#X4#    1 2
    0001	  1	x1#X2#X3#X4     1        5		  11
    0010	  0
    0011	  0
    0100	  1  	X1#X2X3#X4#       2  3
    0101      0
    0110	  1     X1#X2X3X4#           3 4                  11
    0111	  1     X1#X2X3X4              4              10
    1000	  0
    1001	  1     X1X2#X3#X4               5         9
    1010	  0
    1011      0
    1100      1     X1X2X3#X4#                 6
    1101	  1	X1X2X3#X4                  6  7    9
    1110	  0
    1111	  1     X1X2X3X4                      7       10
    -------------------------------------------------------------

Строим таблицу термов более низкого ранга:
    -------------------------------------------------------------
    Пара	X1X2X3X4	Терм    	Пары различающиеся на 1 бит
    -------------------------------------------------------------
    1	000-		X1#X2#X3#          C
    2	0-00		X1#X3#X4#                       < - Result
    3	01-0		X1#X2X4#                        < - Result
    4	011-		X1#X2X3         B
    5	-000		X2#X3#X4#                       < - Result
    6	110-		X1X2X3#		                <-  Result
    7	11-1		X1X2X4                          < - Result
    9	1-01		X1X3#X4                         < - Result
    10	-111		X2X3X4                          < - Result
    11	010-		X1#X2X3#        B  C
    ......
    -------------------------------------------------------------

Сортируем ее по перестановкам:
И ищем термы внутри перестановки которые отличаются на 1 бит:
    -------------------------------------------------------------
    Пара	X1X2X3X4	Терм    	Пары различающиеся на 1 бит
    -------------------------------------------------------------
    1	000-		X1#X2#X3#          C
    4	011-		X1#X2X3         B
    6	110-		X1X2X3#		                <-  Result
    11	010-		X1#X2X3#        B  C
     ----------------------------------------------------------
    3	01-0		X1#X2X4#                        < - Result
    7	11-1		X1X2X4                          < - Result
     ----------------------------------------------------------
    2	0-00		X1#X3#X4#                       < - Result
    9	1-01		X1X3#X4                         < - Result
     ----------------------------------------------------------
    5	-000		X2#X3#X4#                       < - Result
    10	-111		X2X3X4                          < - Result
    ......
    -------------------------------------------------------------

Затем строит пары еще более низкого ранга:
    -------------------------------------------------------------
    Пара	X1X2X3X4	Терм        Пары различающиеся на 1 бит
    -------------------------------------------------------------
    B	01--		x1#X2			        <-  Result
    C	0-0-		X1#X3#                          < - Result
    -------------------------------------------------------------
итд пока не сможем это делать.

Затем выписываем результат от младшего ранга к старшему
(не выписывая термы которые вошли в термы более младшего ранга).

Результат:
    F(X) = X1#X2 + X1#X3# +
         + X1#X3#X4# + X1#X2X4#   + X2#X3#X4# + X1X2X3# +
         + X1X2X4    + X1X3#X4    + X2X3X4

Дальнейшая минимизация связана уже с выведением функции за пределы ДНФ.
(и минимизация числа произведений и сложений).

    = X1#X2 + X1#X3# +
    + X4#(X1#X3# + X1#X2 + X2#X3#) + X1X2X3# +
    + X4 (X1X2   + X1X3# + X2X3)

или	= X1#X2 + X1#X2X4#  + X1X2X4
    + X3# (X1 + X1#X4# + X2#X4# + X1X2 + X1X4) + X2X3X4

Метод Квина-Маккласки очень плохо оптимизирует XOR.
(В реальной жизни XOR надо отслеживать и порождать XOR)


2.6.1.1. ЛОГИКА РИДА-МИЛЛАРА

THIS SECTION IS UNDER CONSTRUCTION

Собственно, где не помогает Квин-Маккласки надо использовать логику
Рида-Миллара, основанную на XOR.
(В реальной жизни получаются комбинации и того и того).

TODO: Методы нахождения покрытий для логики Рида-Миллара


2.6.2. ВЫВОД ЗА ПРЕДЕЛЫ ДНФ

Логическими выражениями в виде ДНФ удобно оперировать, но реальный элементный
базис все таки NAND/NOR, а не AND/OR.

Вывод за пределы ДНФ в NAND.

                                  _____________
                                  _____   _____
F(x1,x2,x3,x4) = x1*x2 + x3*x4 =  x1*x2 * x3*x4

Вывод за пределы ДНФ в NOR

возмем инверсную функцию от F.

                                 _____________________
                                 _________   _________
-                _____________    __   __     __   __
F(x1,x2,x3,x4) = x1*x2 + x3*x4 = (x1 + x2) + (x3 + x4)


2.7. БАЗИС

    Для записи любой логической функции любого числа переменных
можно использовать некоторый необходимый минимум функций называемый БАЗИСОМ

Rang 3
    AND/OR/NOT	используется в нормальной дезъюнктивной форме
            доказательство: карта Карно (см. 2.6)
            все элементарные конъюнкции ранга равного количеству
            переменных функции покрывают все клетки таким образом
            определяя функцию для всех наборов.

Rang 2
    AND/NOT
        X OR Y =   (X#  AND Y#)#

    OR/NOT
        X AND Y =  (X#  OR Y#)#

    задача сведена к AND/OR/NOT

Rang 1
    NOR
        NOT X 	= X NOR X
        X AND Y = X# NOR Y# = (X NOR X) NOR (Y NOR Y)
        X OR  Y = (X# AND Y#)#
        задача сведена к AND/OR/NOT
    NAND
        NOT X = X NAND X
        X NOR Y = (X# NOR #Y)#
        задача сведена к NOR

Вообще для двоичной логики базис должен обладать следующими свойствами:
Функции входящие в него должны иметь веcь набор следующих свойств:
(т.е. одна может иметь одно свойство, другая пару других, но весь базис
должен иметь все свойства):
    не сохранять 0
        функция сохраняет 0, если  F(0,0,...,0) = 0
            x1 x2 | F
            ------+---
            0  0  | 0
            0  1  | X
            1  0  | X
            1  1  | X
    не сохранять 1
        функция сохраняет 1, если  F(1,1,...,1) = 1
        [OR  сохраняет и 0 и 1]
        [XOR cохраняет 0]
            x1 x2 | F
            ------+---
            0  0  | X
            0  1  | X
            1  0  | X
            1  1  | 1
    не cамодвойственны
        Функция самодвойственна, если
        F(x1,x2,..,xN) = F(x1#,x2#,..,xN#)#
        [NOT самодвойственная]
            x1 x2 | F
            ------+---
            0  0  | A
            0  1  | B
            1  0  | B#
            1  1  | A#
    не линейны
        Функция линейна, если ее можно представить в виде
            F = a0 + a1x1 + ... + aNaN
        [Тождественные 0,1,x1,x1#,x2,x2#, XOR и XNOR линейные]
        (линейность в арифметическом смысле)

    не монотонны
        Функция монотонна если она все время увеличивается или
        уменьшается.
        Упорядоченность для рабочих наборов определяется так:
            a = (a1,...,aN)
            b = (b1,...,bN)
        a <= b, если ai <= bi, для всех i
        [OR монотонная, XOR нет]

Пример диаграмм для монотонности

Для случая 2х переменных (1-2-1):

Для случая 3х переменных (1-3-3-1):

В случае 3 переменных (1-4-6-4-1) плоскости не хватает
Приходиться расщеплять зоны.

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

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

      __ __     __    _____________
        F(x1,x2,...,xN) = G(x1,x2,..Xn)

Пример:
                                 _
     для F(a,b) =  a *  b +  a * b

двойственной будет функция:
                                 _
        F'(a,b) = (a + b) * (a + b)

Примеры двойственных функций:

    0	и	1
    AND	и	OR
    XOR	и	EQV
    NAND	и	NOR
    <	и	=>	(IMP и Запрет)
    >	и	<=	(IMP и запрет)

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

Пример:
                         _
    для F(a,b) = a * b + a * b

инверсная функция будет:
        _         _   _         _
    F(a,b) = (a + b) * (a + b)

THIS SECTION IS UNDER CONSTRUCTION

---------------------------------------------------------------------------------
   x1 x2                сохр    сохр           	 само
00 01 10 11	Имя	  0	  1	линейна  двойств   монотонна
---------------------------------------------------------------------------------
0  0  0  0	0	  1       0       1	   0	     1
0  0  0  1      AND       1       1       0        0         1
0  0  1  0      x1>x2     1       0       0        0         0
0  0  1  1      x1        1       1       1        1         1
0  1  0  0      x2>x1     1       0       0        0         0
0  1  0  1      x2        1       1       1        1         1
0  1  1  0      XOR       1       0       1        0         0
0  1  1  1      OR        1       1       0        0         1
1  0  0  0      NOR       0       0       0        0         0
1  0  0  1      XNOR      0       1       1        0         0
1  0  1  0      ~x2       0       0       1        1         0
1  0  1  1      x2->x1    0       1       0        0         0
1  1  0  0      ~x1       0       0       1        1         0
1  1  0  1      x1->x2    0       1       0        0         0
1  1  1  0      NAND      0       0	  0        0         0
1  1  1  1      1         0       1       1        0         1
---------------------------------------------------------------------------------
Базис должен содержать 0 во всех классах.

Из этого следует что можно сделать базис из:
    импликации и константы 0


2.8. ПОЛИНОМАЛЬНАЯ ФОРМА

В системах счистления в остаточных классах (ССОК) двоичные функции
можно представлять в полиномальном виде.
    Умножение	-   AND
    Сложение	-   XOR	(т.е. сложение но в пределах 1 бита):

F = A0 (+) A1*X1 (+) A2*X2 (+) A3*X1*X2

    ----------------------------------------------------------------------
           X1X2            		   F
    ----------------------------------------------------------------------
    00	01	10	11	A0	A1	A2	A3     Имя
    ----------------------------------------------------------------------
    0	0	0	0	0	0	0	0      0
    0	0	0	1	0	0	0	1      AND
    0	0	1	0	0	1	0	1      x1<-x2
    0	0	1	1	0	1	0	0      x1
    0	1	0	0	0	0	1	1      x2<-x1
    0	1	0	1	0	0	1	0      x2
    0	1	1	0	0	1	1	0      XOR
    0	1	1	1	0	1	1	1      OR
    1	0	0	0	1	1	1	1      NOR
    1	0	0	1	1	1	1	0      EQV
    1	0	1	0       1       0	1	1      x1->x2
    1	0	1	1       1       1	0	1      x2->x1
    1	1	0	0       1       1	0	0      x1#
    1	1	0	1       1       0       1       0      x2#
    1	1	1	0       1       0	0	1      NAND
    1	1	1	1       1       0	0	0      1
    ----------------------------------------------------------------------

    --------------------------------------------
    0		=  0
    AND(x1,x2)      =                      x1*x2
    x1<-x2		=        x1 (+)        x1*x2
    x1		=        x1
    x2<-x1		=               x2 (+) x1*x2
    x2		=               x2
    XOR		=        x1 (+) x2
    OR		=        x1 (+) x2 (+) x1*x2
    NOR		=  1 (+) x1 (+) x2 (+) x1*x2
    EQV		=  1 (+) x1 (+) x2
    x1->x2		=  1 (+)        x2 (+) x1*x2
    x2->x1	        =  1 (+) x1 (+)        x1*x2
    x1#		=  1 (+) x1
    x2#		=  1 (+)        x2
    NAND		=  1 (+)               x1*x2
    1		=  1
    --------------------------------------------

Пример:
    X1  X2 | F |  A0    A1*X1   A2*X2  A3*X1*X2
    -------+---+----------------------------------
    0   0  | 1 |  1      0       0        0
    0   1  | 1 |  1	     0       0        0
    1   0  | 0 |  1      1       0        0
        1   1  | 0 |  1      1       0        0

Как вычислять:

    X1 X2  | F |  A0    A1*X1   A2*X2  A3*X1*X2   |  A0  A1  A2  A3
    -------+---+----------------------------------+-----------------
    0  0   | 1 |  ?      0       0      0	      |  ?   ?   ?   ?
    0  0   | 1 |  1      0       0      0         |  ?   ?   ?   ?
    0  0   | 1 |  1      0       0      0         |  1   ?   ?   ?
    -------+---+----------------------------------+-----------------
    0  1   | 0 |  1      0       ?      0         |  1   ?   ?   ?
    0  1   | 0 |  1      0       1      0         |  1   ?   ?   ?
    0  1   | 0 |  1      0       1      0         |  1   ?   1   ?
    -------+---+----------------------------------+-----------------
    1  0   | 1 |  1      ?       0      0         |  1   ?   1   ?
    1  0   | 1 |  1      0       0      0         |  1   ?   1   ?
    1  0   | 1 |  1      0       0      0         |  1   0   1   ?
    -------+---+----------------------------------+-----------------
    1  1   | 1 |  1      0       1      ?         |  1   0   1   ?
    1  1   | 1 |  1      0       1      1         |  1   0   1   ?
    1  1   | 1 |  1      0       1	    1         |  1   0   1   1

Собственно логическую функцию одной переменной можно представить в виде
полинома 1 степени:
F(x) =	a0 + a1 * x	(пишем + подразумеваем (+)

    ------------------------------------
              a1a0
    x	00	01	10	11
    ------------------------------------
    0	0	1	0	1
    1	0	1       1       0
    ------------------------------------
    F	0	1	x	x#
    ------------------------------------

Функции с большим числом переменных получаются перемножением полиномов
функций с одной переменной.
Например для двух переменных:

F(x1,x2) = (a0 + a1*x1) * (b0 + b1*x2) =
     = a0*b0  + a1*b0*x1 + a0*b1*x2 + a1*b1*x1*x2  =
       -----    -----      -----      -----
     =  A0    +  A1 * x1 +  A2 * x2 + A3 * x1 * x2


2.8.1. РАЗЛОЖЕНИЕ ЛОГИЧЕСКИХ ФУНКЦИЙ

  Разложение Шеннона

Разложение Шенонна:
                        __
F(X1,...,Xp, ..., Xn) = Xp * F(X1, ..., 0,...Xn) + Xp * F(X1,...,1,..Xn)

Обозначим G0 = F(X1,...,0,...Xn),
      G1 = F(X1,...,1,...Xn)

и в самом деле, если Xp = 0, то

    F = 1 * G0 + 0 * G1 = G0 = F(X1,...,0,..Xn)

а если Xp = 1, то

    F = 0 * G0 + 1 * G1 = G1 = F(X1,...,1,...Xn).

Из двойственности булевой алгебры следует, что есть еще разложение вида:
                                                 _
F(X1,...,Xp,...,Xn) = [Xp + F(X1,...,0,..Xn)] * [Xp + F(X1,...,1,...Xn)]

Все тоже самое:
Если Xp = 0, то:

    F = (0 + G0) * (1 + G1) = G0 * 1 = G0 = F(X1,...,0,...Xn)

а если Xp=1 то:

    F = (1 + G0) * (0 + G1) = 1 * G1 = G1 = F(x1,...,1,...Xn)

  Разложение Рида

Как известно, если X * Y = 0 то X + Y = X (+) Y

    -----------------------------
    X  Y	X*Y	X+Y	X(+)Y
    -----------------------------
    0  0    0	0	0
    0  1	0	1	1
    1  0	0	1	1
    -----------------------------
    1  1	1	1	0
    -----------------------------

Рассмотрим Разложение Шеннона:
            _
    F = Xp * G0 + Xp * G1

         _                            _
    (Xp * G0) * (Xp * G1) = (Xp * Xp) * (G0 * G1) = 0 * G0 * G1 = 0

Таким образом мы можем заменить в разложении Шеннона OR на XOR:
        _
    F = Xp * G0 (+) Xp * G1 =

      = (1 (+) Xp) * G0 (+) Xp * G1 =

      = G0 (+) Xp * G0 (+) Xp * G1 =

          = G0 (+) (G0 (+) G1) * Xp

Это называется разложением Рида.

Попробуем разложить функцию 2 переменных по обеим переменным:
(пишем + имеем в виду XOR):

F(x2,x1) = F(0,x1) + [F(0,X1) + F(1,X1)] * x2  =
     = F(0,0)  + [F(0,0) + F(0,1) ] * x1 +
    [ { F(0,0)  + [F(0,0) + F(0,1) ] * x1 } +
      { F(1,0}  + [F(1,0) + F(1,1) ] * x1 } ] * x2 =

    =  F(0,0)  +
         [ F(0,0)  + F(0,1) ] * x1 +
     [ F(0,0)  + F(1,0) ] * x2 +
     [ F(0,0)  + F(0,1) + F(1,0) + F(1,1) ] * x1 * x2

Таким образом:

    F = A0 + A1*x1 + A2*x2 + A3*x1*x2 имеет коэффициенты:

    A0 = F(0,0)
    A1 = F(0,0) (+) F(0,1)
    A2 = F(0,0) (+) F(1,0)
     A3 = F(0,0) (+) F(0,1) (+) F(1,0) (+) F(1,1)

Попробуем выразить импликацию x1->x2

    --------------
    x2 x1	x1->x2
    --------------
    0  0	1
    0  1	0
    1  0	1
    1  1	1
    --------------

    A0 = 1
    A1 = 1 (+) 0 = 1
    A2 = 1 (+) 1 = 0
    A3 = 1 (+) 0 (+) 1 (+) 1 = 1

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

    IMP_x1_x2(x2,x1) = 1 + x1 + x1*x2


2.9. СИММЕТРИЧЕСКИЕ ФУНКЦИИ

Def
====
Функция n аргументов называется симметрической
если она инвариантна относительно перестановки своих
аргументов.

  Один аргумент

---------------------
S1	S0
---------------------
-	-	0
-	+	NOT1
+	-	X1
+	+	1
---------------------

Вырожденный случай

S0(1) = X
S1(1) = NOT(X)

  Два аргумента

-----------------------------
S2	S1	S0
-----------------------------
-	-	-	0
-	-	+	NOR2 (S0)
-	+	-	XOR2 (S1)
-	+	+	NAND2
+	-	-	AND2 (S2)
+	-	+	XNOR2
+	+	-	OR2
+	+	+	1
-----------------------------

XOR2  = S1(2)
XNOR2 = S0(2) + S2(2)
AND2  = S2(2)
OR2   = S1(2) + S2(2)
NAND2 = S0(2) + S1(2)
NOR2  = S0(2)

S0(2):
(он же NOR2)

-----------------------
A   B  SUM(1s)  S0(2)
-----------------------
0   0	   0*	 1
0   1      1     0
1   0      1     0
1   1      2     0
-----------------------

S1(2):
(он же XOR2)

-----------------------
A   B  SUM(1s)  S1(2)
-----------------------
0   0	   0     0
0   1      1*    1
1   0      1*    1
1   1      2     0
-----------------------

S2(2):
(он же AND2)

-----------------------
A   B  SUM(1s)  S2(2)
-----------------------
0   0	   0     0
0   1      1     0
1   0      1     0
1   1      2*    1
-----------------------

Затем суперпозиции:

XNOR2:
(сумма единиц равна 0 или 2)

-----------------------
A   B  SUM(1s) S{0,2}(2)
-----------------------
0   0	   0*    1
0   1      1     0
1   0      1     0
1   1      2*    1
-----------------------

OR2:
(сумма единиц равна 1 или 2)

-----------------------
A   B  SUM(1s) S{1,2}(2)
-----------------------
0   0	   0     0
0   1      1*    1
1   0      1*    1
1   1      2*    1
-----------------------

NAND2:
(сумма единиц равна 0 или 1)

-----------------------
A   B  SUM(1s) S{0,1}(2)
-----------------------
0   0	   0*    1
0   1      1*    1
1   0      1*    1
1   1      2     0
-----------------------

  Три аргумента

-------------------------------------------
S3	S2	S1	S0
-------------------------------------------
-	-	-	-	0
-	-	-	+	NOR3  (S0)
-	-	+	-       S1
-	-	+	+	MIN3
-	+	-	-	S2
-	+	-	+	XNOR3
-	+	+	-       mean
-	+	+	+	NAND3 (S3)
+	-	-	-	AND3
+	-	-	+       mean#
+	-	+	-	XOR3
+	-	+	+       S2#
+	+	-	-	MAJ3
+	+	-	+	S1#
+	+	+	-	S0#
+	+	+	+	1
-------------------------------------------

S0(3):
(он же NOR3)

------------------------
A  B  C  SUM(1s)  S0(3)
------------------------
0  0  0	    0*	  1
0  0  1     1     0
0  1  0     1     0
0  1  1     2     0
1  0  0     1     0
1  0  1     2     0
1  1  0     2     0
1  1  1     3     0
------------------------

S1(3):

------------------------
A  B  C  SUM(1s)  S1(3)
------------------------
0  0  0	    0     0
0  0  1     1*    1
0  1  0     1*    1
0  1  1     2     0
1  0  0     1*    1
1  0  1     2     0
1  1  0     2     0
1  1  1     3     0
------------------------

S2(3):

------------------------
A  B  C  SUM(1s)  S2(3)
------------------------
0  0  0	    0     0
0  0  1     1     0
0  1  0     1     0
0  1  1     2*    1
1  0  0     1     0
1  0  1     2*    1
1  1  0     2*    1
1  1  1     3     0
------------------------

S3(3):
(он же AND3)

------------------------
A  B  C  SUM(1s)  S3(3)
------------------------
0  0  0	    0     0
0  0  1     1     0
0  1  0     1     0
0  1  1     2     0
1  0  0     1     0
1  0  1     2     0
1  1  0     2     0
1  1  1     3*    1
------------------------

Остальные функции в этом классе делаются суперпозицией:

Мажоритарная функция:
(если число единиц равно 2 или 3)

--------------------------
A  B  C  SUM(1s) S{2,3}(3)
--------------------------
0  0  0	    0      0
0  0  1     1      0
0  1  0     1      0
0  1  1     2*     1
1  0  0     1      0
1  0  1     2*     1
1  1  0     2*     1
1  1  1     3*     1
--------------------------

Функция среднего
(если число единиц равно 1 или 2)

--------------------------
A  B  C  SUM(1s) S{1,2}(3)
--------------------------
0  0  0	    0     0
0  0  1     1*    1
0  1  0     1*    1
0  1  1     2*    1
1  0  0     1*    1
1  0  1     2*    1
1  1  0     2*    1
1  1  1     3     0
--------------------------

(если число единиц равно 0 или 3)

--------------------------
A  B  C  SUM(1s) S{0,3}(3)
--------------------------
0  0  0	    0*    1
0  0  1     1     0
0  1  0     1     0
0  1  1     2     0
1  0  0     1     0
1  0  1     2     0
1  1  0     2     0
1  1  1     3*    1
--------------------------

XOR3
(если число единиц равно 1 или 3)

--------------------------
A  B  C  SUM(1s) S{1,3}(3)
--------------------------
0  0  0	    0     0
0  0  1     1*    1
0  1  0     1*    1
0  1  1     2     0
1  0  0     1*    1
1  0  1     2     0
1  1  0     2     0
1  1  1     3*    1
--------------------------

XNOR3
(если число единиц равно 0 или 2)

--------------------------
A  B  C  SUM(1s) S{0,2}(3)
--------------------------
0  0  0	    0*     1
0  0  1     1      0
0  1  0     1      0
0  1  1     2*     1
1  0  0     1      0
1  0  1     2*     1
1  1  0     2*     1
1  1  1     3      0
--------------------------

  Четыре аргумента

К сожалению на плоскости придется представлять в виде
Диаграммы Эдвардса.

S0(4):

S1(4):

S2(4):

S3(4):

S4(4):

Соответсвенно суперпозиции:

XOR4
(если число единиц равно 1 или 3)

В принципе симметрические функции можно использовать
и для подсчета Population Count.

Случай для 2х переменных:
popcnt(2,bit0) = S1(2)
popcnt(2,bit1) = S2(2)

Случай для 3х переменных:
popcnt(3,bit0) = S1(3) + S3(3)
popcnt(3,bit1) = S2(3) + S3(3)

случай для 4х переменных:
popcnt(4,bit0) = S1(4) + S3(4)
popcnt(4,bit1) = S2(4) + S3(4)
popcnt(4,bit2) = S4(4)

случай для 5ти переменных:
popcnt(5,bit0) = S1(5) + S3(5) + S5(5)
popcnt(5,bit1) = S2(5) + S3(5)
popcnt(4,bit2) = S4(5) + S5(5)

  Реализация симметрических функций

Реализация симметрических функций на базе
регулярных ДНФ и КНФ - требует больших ресурсов.

Гораздо проше они реализуются с помощью мостиковых
схем.

Симметрическая Структура Шеннона
позволяет получить все симметрические функции.

  Частные случаи

Для получения конкретной симметрической функции
можно использовать части из симметрической структуры Шеннона.
(понятно что S0 и Smax проще получить обычным способом)


2.10. ЛОГИКА БОЛЕЕ ВЫСОКИХ ПОРЯДКОВ

THIS SECTION IS UNDER CONSTRUCTION

  Отрицание Поста

    -
    X =  |  0   1   ...  k-2  k-1 |   = x + 1 (mod k)
         |  1   2   ...  k-1  0   |

    _
    _
    X = X + 2 (mod k)

  Отрицание Лукашевича

    ~X = |  0    1    2   ...  k-1 |  = (k-1) - X (mod k)
         | k-1  k-2  k-3  ...   0  |

    ~(~X) = X

  Negate

    -X = |  0    1    2   ...  k-1  |
         |  0   k-1  k-2  ...  1    |

    -X + X = 0

          ____
    X = - (~X)

  Обобщения отрицания

    J{i}(X)  =  |  k-1,  x = i 	0 <= i <= k-1
            |    0,  x != i

    j{i}(X)  =  |    1,  x = i 	0 <= i <= k-1
            |    0,  x != i

Разность переменной X и константы i

    X - i = X + (K - I)

    Максимум
    Минимум
    Сложение по модулю k
    Произведение по модулю k

  Усеченная разность

          .
    X - Y = |   X - Y,   X >= Y
        |   0,	     X < Y

             .    .
    MIN(X,Y) = X - (X - Y)

  Импликация

                   |  K - 1 - X + Y,  X >= Y
    IMP(X,Y) = |  K - 1,	      X <  Y

  Система Россера-Туркетта

Система функций
    {0, 1, ..., k-1, J{0}(X),...J{k-1}(X),min(X,Y),max(X,Y)}

называется системой Россера-Туркетта.

Система Россера-Туркетта полна в P{k}

Всего в P{k} существует 2^k-2 классов, сохраняющих непустые собственные множества
причем все они попарно различны и ни один из них не содержиться в другом

Пример класса - функции сохраняющие 0.

При любом значении k - следущие системы являются полными

    1)	Система Россера-Туркетта
    2)	{0, ..., k-1, j{0},...j{k-1}, +, *}
                     _
    3)	Система Поста	{X, max(X,Y)}

          _
    4)	{X, min(X,Y)}

                  .
    5)	{1, K-1, X-Y}

    6)	Функция Уэбба  V(X,Y)

  Функция Уэбба

     ________
    MAX(X,Y) = MAX(X,Y) + 1

Еще возможные системы:

           .
    {k-1, X-Y, X+Y}
               .
    {~X, X+2, X-Y}
                 .
    {-X, 1-X^2, X-Y}

                 .
    {X + Y, (~X) - 2Y}


2.11.1. ТРОИЧНАЯ ЛОГИКА

Бывает логика более сложных порядков чем двоичная.

  Троичная логика

Троичная логика
(Ternary logic)
мы смотрим сбалансированный вариант.
    ---------------------------------------
    0	ложь		Minimal value
    i	фиг знает
    1	истина		maximum value
    ---------------------------------------

Расширенный вариант диаграммы Венна:

Для однооперандных функций:
Два вложенных круга, внутри внутреннего операнд = 1, между внешним и внутреннем
операнд = i, снаружи внешнего операнд = 0.
Значения:
    0	сплошной белый
    i	сплошной зеленый
    1	штрихованный черный

Для двухоперандных функций:

Два двойных круга и их пересечения.
Обратите внимание что зоне ii={A=i, B=i} соответсвуют два региона:
один выделен черным, другой зеленым.

  Однооперандные функции

    ---------------------------
    X	0	i	1
    ---------------------------
F0		0	0	0	тождественный 0
F1		0	0	i	Сдвиг вниз (Shift down) (слабый == 1)
F2		0	0	1	Сильный == 1
F3		0	i	0	Слабый  == i
F4		0	i	i	Слабый  != 0
F5		0	i	1       повторение
F6		0	1	0	Сильный ==i
F7		0	1	i	Обмен i и 1    (Negation)
F8		0	1	1	Сильный != 0
F9		i	0	0	Слабый  == 0
F10		i	0	i	Слабый  != i
F11		i	0	1	Oбмен i и 0
F12		i	i	0	Слабый  != 1
F13		i	i	i    	тождественное i
F14		i	i	1
F15		i	1	0	Вращение вниз (Rotate down)
F16		i	1	i
F17		i	1	1	Сдвиг вверх (Shift Up)
F18		1	0	0	Cильный == 0
F19		1	0	i	Вращение вверх (Rotate up)
F20		1	0	1	Сильный != i
F21		1	i	0	инверсия (обмен 0 и 1)
F22		1	i	i
F23		1	i	1
F24		1	1	0	Сильный != 1
F25		1	1	i
F26		1	1	1	тождественная 1
    ---------------------------

  NOT

Отрицание:
    ----------
    X	X#
    ----------
    0	1
    i	i
    1	0
    ----------
    -	+
    0	0
    +	-
    ----------

  Shift Up

    ----------
    X       F
    ----------
    0	i
    i	1
    1	1
    ----------
    -	0
    0	+
    +	+
    ----------

    +---+
    | 1 |
    +---+
      ^
      |
    +---+
    | i |
    +---+
      ^
      |
    +---+
    | 0 |
    +---+

  Shift Down

    ----------
    X	F
    ----------
    0	0
    i	0
    1	i
    ----------
    -	-
    0	-
    +	0
    ----------

    +---+
    | 1 |
    +---+
      |
          V
    +---+
    | i |
    +---+
      |
      V
    +---+
    | 0 |
    +---+

  Rotate Up

    ----------
    X       F
    ----------
    0	i
    i	1
    1	0
    ----------
    -	0
    0	+
    +	-
    ----------

    +---+
    | 1 |----+
    +---+    |
      ^      |
      |      |
    +---+    |
    | i |    |
    +---+    |
      ^      |
      |      |
    +---+    |
    | 0 |<---+
    +---+

  Rotate Down

    ----------
    X	F
    ----------
    0	1
    i	0
    1	i
    ----------
    -	+
    0	-
    +	0
    ----------

    +---+
    | 1 |<---+
    +---+    |
      |      |
      v      |
    +---+    |
    | i |    |
    +---+    |
      |      |
      v      |
    +---+    |
    | 0 |----+
    +---+

  Сравнения

X == A

Ecли X == A то результат 1 (если сильное сравнение), i (если слабое сравнение).
иначе 0.

Пример сильного сравнения == 1:

    ----------
    X     ==1S
    ----------
    0       0
    i	0
    1	1
    ----------
    -	-
    0	-
    +	+
    ----------

Пример слабого сравнения == 1:
    ----------
    X     ==1W
    ----------
    0       0
    i	0
    1	i
    ----------
    -	-
    0	-
    +	0
    ----------

Пример сильного сравнения <> 1:
    ----------
    X     !=1S
    ----------
    0       1
    i	1
    1	0
    ----------
    -	+
    0	+
    +	-
    ----------

Пример слабого сравнения <> 1:
    ----------
    X     !=1W
    ----------
    0       1
    i	1
    1	i
    ----------
    -	+
    0	+
    +	0
    ----------

  Некоторые двухоперандные функции

В троичной логике только 729 коммутативных двухоперандных функций из 19,683
т.е. таких что F(A,B) = F(B,A)

  AND

 X AND Y = MIN(X,Y)

    ------------
    X  Y |	AND
    -----+------
    0  0 |  0
    0  i |  0
    0  1 |  0
    i  0 |  0
    i  i |  i
    i  1 |  i
    1  0 |  0
    1  i |  i
    1  1 |  1
    ------------

    --+----------
      | -  0  +
    --+----------
    - | -  -  -
    0 | -  0  0
    + | -  0  +
    --+----------

  OR

 X OR  Y = MAX(X,Y)

    ------------
    X  Y |	OR
    -----+------
    0  0 |  0
    0  i |  i
    0  1 |  1
    i  0 |  i
    i  i |  i
    i  1 |  1
    1  0 |  1
    1  i |  1
    1  1 |  1
    ------------

    --+----------
      | -  0  +
    --+----------
    - | -  0  +
    0 | 0  0  +
    + | +  +  +
    --+----------

  XOR

Как вычислять логику более высшего порядка:

    Если при перемееном аргументе результат меняется (при его
изменении) то ставится неопределенное значение.

Пример вычислений XOR:

    XOR |  0  1		двоичный XOR
    ----+-------
      0 |  0  1
      1 |  1  0

    ----------------------------------------------
    AB        Local				Result
    ----------------------------------------------
    00	0(+)0 = 0			0
    0i	0(+)0 = 0   0(+)1 = 1		i
    01	0(+)1 = 1			1
    i0	0(+)0 = 0   1(+)0 = 1		i
    ii	0(+)0 = 0   0(+)1 = 1  ...
        1(+)0 = 1   1(+)1 = 0           i
    i1	0(+)1 = 1   1(+)1 = 0		i
    10	1(+)0 = 1			1
    1i	1(+)0 = 1   1(+)1 = 0		i
    11	1(+)1 = 0			0
    ----------------------------------------------

Получаем результат:
    ------------
    X  Y |	XOR
    -----+------
    0  0 |  0
    0  i |  i
    0  1 |  1
    i  0 |  i
    i  i |  i
    i  1 |  i
    1  0 |  1
    1  i |  i
    1  1 |  0
    ------------

    XOR  |  0  i  1
    -----+-----------
       0 |  0  i  1
       i |  i  i  i
       1 |  1  i  0

    --+----------
      | -  0  +
    --+----------
    - | -  0  +
    0 | 0  0  0
    + | +  0  -
    --+----------

  EQV

    EQV(X,Y) = NOT (XOR(X,Y))

    ------------
    X  Y |	EQV
    -----+------
    0  0 |  1		Экивалентен ли 0 - 0           : да
    0  i |  i		Экивалентен ли 0 - фиг знает   : фиг знает
    0  1 |  0
    i  0 |  i
    i  i |  i               Экивалентен ли Фиг знает - фиг знает : фиг знает
    i  1 |  i
    1  0 |  0
    1  i |  i
    1  1 |  1
    ------------

    --+----------
      | -  0  +
    --+----------
    - | +  0  -
    0 | 0  0  0
    + | -  0  +
    --+----------

  NAND

    NAND(X,Y) = NOT (AND(X,Y))

    ------------
    X  Y |	NAND
    -----+------
    0  0 |  1
    0  i |  1
    0  1 |  1
    i  0 |  1
    i  i |  i
    i  1 |  i
    1  0 |  1
    1  i |  i
    1  1 |  0
    ------------

    --+----------
      | -  0  +
    --+----------
    - | +  +  +
    0 | +  0  0
    + | +  0  -
    --+----------

  NOR

    NOR(X,Y) = NOT((OR(X,Y))

    ------------
    X  Y |	NOR
    -----+------
    0  0 |  1
    0  i |  i
    0  1 |  0
    i  0 |  i
    i  i |  i
    i  1 |  0
    1  0 |  0
    1  i |  0
    1  1 |  0
    ------------

    --+----------
      | -  0  +
    --+----------
    - | +  0  -
    0 | 0  0  -
    + | -  -  -
    --+----------

  IMP

Помним что функция несиммитричная

    ------------
    X  Y |	X->Y
    -----+------
    0  0 |  1
    0  i |  1		0->0 = 1   0->1 = 1
    0  1 |  1
    i  0 |  i               0->0 = 1   1->0 = 0
    i  i |  i               0->0 = 1   0->1 = 1   1->0 = 0  1->1=1
    i  1 |  1		0->1 = 1   1->1 = 1
    1  0 |  0
    1  i |  i               1->0 = 0   1->1 = 1
    1  1 |  1
    ------------

    --+----------
      | -  0  +
    --+----------
    - | +  +  +
    0 | 0  0  0
    + | -  0  +
    --+----------

А сейчас мы рассмотрим некоторые интерестные двухоперандные функции:

  Исключающий MAX

XMAX:
    F = MAX(A,B), если A != B
        0	    , если A == B
    (имейте в виду - это не XOR).

      AB |  0   i   1
    -----+--------------
       0 |  0   i   1
       i |  i   0   1
       1 |  1   1   0

    --+----------
      | -  0  +
    --+----------
    - | -  0  +
    0 | 0  -  +
    + | +  +  -
    --+----------

  Инверсно Исключающий MIN:

IXMAX:

    F = MIN(A,B), если A != B
        1	    , если A == B

      AB |  0   i   1
    -----+--------------
       0 |  1   0   0
           i |  0   1   i
           1 |  0   i   1

    --+----------
      | -  0  +
    --+----------
    - | +  -  -
    0 | -  +  0
    + | -  0  +
    --+----------

  Mean

Mean:
    Смотрит насколько "средние" операнды
    Если ii, то возращает 1
    Если iX или Xi, то возращает i
    Иначе 0

      AB |  0  i   1
    -----+-------------
       0 |  0  i   0
       i |  i  1   i
       1 |	0  i   0

    --+----------
      | -  0  +
    --+----------
    - | -  0  -
    0 | 0  +  0
    + | -  0  -
    --+----------

  Magnitude

Magnitude:
    Сравнение
    (Функция нессимитричная)
    Возращает 0, если A < B
          i, если A = B
          1, если A > B

         |     B
         | 0   i   1
    -----+-----------
       0 | i   0   0
    A  i | 1   i   0
       1 | 1   1   i

    --+----------
      | -  0  +
    --+----------
    - | 0  -  -
    0 | +  0  -
    + | +  +  0
    --+----------

  Число логических функций

Для двоичной системы счисления имеем:
    число однооперандных функций = 2^2 = 4
    число двухоперандных функций = 2^4 = 16

Для троичной системы счисления имеем:
    число однооперандных функций  = 3^3 = 27
    число двухоперандных функций  = посчитайте сами  (3^9)
    (ясное дело, что мы не будем здесь приводить эти функции).

    -----------------------------------------------------
    00  0i  01  i0  ii  i1  10  1i  11	входной набор
    -----------------------------------------------------
    cколько комбинаций? 3 для каждого значения входного
    набора, всего = 3^9 = 19683
    -----------------------------------------------------

    А вообще говоря число функций равно 3^(3^N), где N число аргументов
    для N=1  =                27
    для N=2  =            19,638
    для N=3  = 7,625,597,484,987

  Трит и трайт

трит	(0,i,1)
    единица информации - ячейка которая может быть в одном из трех состояний

    не стоит думать что
        1 трит  = 1.5 бита
    потому что:
        2 трита хранят = 3*3   = 9 комбинаций
        3 бита  хранят = 2*2*2 = 8 комбинаций
    т.е. 2 трита > 3 бита.

    На самом деле равные единицы информации - должны хранить равное число
    комбинаций.
    Имеем - есть некоторое число N:

        N = 2^m
        N = 3^k

        2^m = 3^k

    прологарифмируем по основанию e:

        m * ln 2 = k * ln 3

             k * ln3
        m = ---------
               ln 2
                             1 * ln 3         1.098612
    соответсвенно 1 трит =  ---------- бит =  --------- бит = 1.5849 бит
                              ln 2            0.693147

    соответсвенно 2 трита = 1.5849 * 2 = 3.1698 бит

трайт	(как правило 6 тритов).
    6 тритов могут хранить 3^6 = 729 состояний

    1 трайт = 1.5849 * 6 бит = 9.5094 бит = 9.5094 / 8 байт = 1.1887 байт

    3^1	3
    3^2	9
    3^3	27
    3^4	81
    3^5	243
    3^6	729
    3^7	2187
    3^8	6561
    3^9	19683

    3^10	59049

  Полиномальная форма

Полиномальная форма троичных функций:

для функции с 1м переменным:

    F = A0 + A1*X + A2*X^2

для функции с 2мя переменными
    F = A0 + A1*X1 + A2*X2 + A3*X1^2 + A4*X2^2 + A5*X1*X2 +
                 + A6*X1^2*X2 + A7*X1*X2^2 + A8*X1^2*X2^2

Полиномальная форма троичных функций очень важна практически, т.к.
элементы для оптических вычислений делают + и * на 3-ной ССОК.

    {0,1,2,...p-1}		p - основание системы счисления

    F(0) = c0
    F(1) = c1
    ...
    F(p-1) = C{p-1}		в фигурных скобках индекс

    F(x) = SUM{I=0..p-1} (aI*x^I)  (mod p)

    c0 = a0
    c1 = a0 + a1 +... + a{p-1}
    c2 = a0 + 2*a1 + 2^2*a2+ .. + 2^(p-1)*a{p-1}
    ....
    c{p-1} = a0 + (p-1)*a1 + (p-1)^2*s2 + ... + (p-1)^(p-1)a{p-1}

Для многовходовых:
    F(x,y) = fo(x) + f1(x)y + f2(x)*y^2 + ... + f{p-1}(x)*y^(p-1) (mod p)
    где
    fI(x) = a{0,i} + a{1,i}*x + a{2,i}*x^2 + .. + a{p-1,i}*x^(p-1)

Рассмотрим троичные функции с 1 переменной:

    F = A0 + A1*X + A2*X^2

    ------------------------
               X
    A2  A1  A0	0  1  2
    ------------------------
    0   0   0	0  0  0
    0   0   1	1  1  1
    0   0   2	2  2  2
    0   1   0	0  1  2
    0   1   1	1  2  0
    0   1   2	2  0  1
    0   2   0	0  2  1
    0   2	1	1  0  2
    0   2   2	2  1  0
    1   0   0	0  1  1
    1   0   1	1  2  2
    1   0   2	2  0  0
    1   1   0	0  2  0
    1   1   1	1  0  1
    1   1   2	2  1  2
    1   2   0	0  0  2
    1   2   1	1  1  0
    1   2   2	2  2  1
    2   0   0	0  2  2
    2   0   1	1  0  0
    2   0   2	2  1  1
    2   1   0	0  0  1
    2   1   1	1  1  2
    2   1   2	2  2  0
    2   2   0	0  1  0
    2   2   1	1  2  1
    2   2   2	2  0  2
    ------------------------

Как искать коэфициенты:

    F(0) = A0 + A1 * 0 + A2 * 0 = A0
    F(1) = A0 + A1     + A2     = A0 + A1 + A2
    F(2) = A0 + 2*A1   + A2     = A0 + 2*A1 + A2

пример:
    пусть F(0) = 1, F(1) = 2, F(2) = 1
    тогда
        A0 = 1

        A0 + A1 + A2 = 2
        1  + A1 + A2 = 2
        A1 + A2 = 1

        1  + 2*A1 + A2 = 1
        1  + A1 + (A1 + A2) = 1
        1  + A1 + 1 = 1
        A1 = -1		(т.е. 2)
        A1 = 2

        A1 + A2 = 1
        2  + A2 = 1
        A2 = -1		(т.е 2)
        A2 = 2

    ---------------------------------------------------
               X
    A2  A1  A0	0  1  2		Полином
    ---------------------------------------------------
    0   0   0	0  0  0		0
    2   1   0	0  0  1         2x^2 + x
    1   2   0	0  0  2		x^2  + 2x
    2   2   0	0  1  0 	2x^2 + 2x
    1   0   0	0  1  1		x^2
    0   1   0	0  1  2		x
    1   1   0	0  2  0		x^2  + x
    0   2   0	0  2  1		2x
    2   0   0	0  2  2		2x^2
    2   0   1	1  0  0		2x^2 + 1
    1   1   1	1  0  1		x^2  + x + 1
    0   2	1	1  0  2		2x + 1
    1   2   1	1  1  0		x^2 + 2x + 1
    0   0   1	1  1  1		1
    2   1   1	1  1  2		2*x^2 + x + 1
    0   1   1	1  2  0		x + 1
    2   2   1	1  2  1		2*x^2 + 2x + 1
    1   0   1	1  2  2		x^2 + 1
    1   0   2	2  0  0         x^2 + 2
    0   1   2	2  0  1		x + 2
    2   2   2	2  0  2		2x^2 + 2x + 2
    0   2   2	2  1  0         2x + 2			NOT
    2   0   2	2  1  1		2x^2 + 2
    1   1   2	2  1  2		x^2 + x + 2
    2   1   2	2  2  0		2x^2 + x + 2
    1   2   2	2  2  1		x^2 + 2x + 2
    0   0   2	2  2  2		2
    ---------------------------------------------------

как искать коэфициенты для троичной функции с 2 переменными:

    F(x,y) = A0 + A1*x  + A2*x^2   + A3*y      + A4*y^2 +
            + A5*xy + A6*x^2*y + A7*x*y^2  + A8*x^2*y^2

F(0,0) = A0                  	определяем A0
F(1,0) = A0 + A1 + A2
F(2,0) = A0 + 2*A1 + A2		определяем A1,A2
F(0,1) = A0 + A3 + A4
F(0,2) = A0 + 2*A3 + A4		определяем A3,A4

F(1,1) = A0 +   A1 + A2 +   A3 + A4 +   A5 +   A6 +   A7 + A8
F(2,1) = A0 + 2*A1 + A2 +   A3 + A4 + 2*A5 +   A6 + 2*A7 + A8
F(1,2) = A0 +   A1 + A2 + 2*A3 + A4 + 2*A5 + 2*A6 +   A7 + A8
F(2,2) = A0 + 2*A1 + A2 + 2*A3 + A4 +   A5 + 2*A6 + 2*A7 + A8

из последних 4 уравнений определяем A5,A6,A7,A8

  Базис

Базис для троичной логики найти гораздо труднее.
Но существует функция которая является базисом в любой логике.
Это функция Уэбба

    W(X,Y) =  X + 1, если X == Y
          0    , если X != Y

        (X + 1 в арифметическом смысле)

Для двоичной системы это будет:
        ----------
        XY      W
        ----------
        00	1	зто будет NOR
        01      0
        10      0
        11      0
        ----------

Для троичной системы:
        ----------
        XY	W
        ----------
        00	i
        0i      0
        01      0
        i0      0
        ii      1
        i1      0
        10      0
        1i      0
        11      0
        ----------

    --+----------
      | -  0  +
    --+----------
    - | 0  0  0
    0 | 0  +  0
    + | 0  0  -
    --+----------

  Арифметика

В логическом смысле троичную логику мы рассмотрели
Теперь рассмотрим ее в арифметическом смысле:

    Цифра | Значение
    ------+-------
    0     |  0
    1     |  i
    2     |  1

Имеем в виду, что у нас есть принципиально 2 арифметики
    троичная система  {0,1,2}
и	сбалансированная троичная система {-,0,+} = {-1,0,+1}
соответсвенно арифметические функции у этих систем принципиально разные

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

        |
    A+B |   0       1       2
    ----+------------------------
     0  |  00      01      02
     1  |  01      02      10	старший бит - перенос
     2  |  02      10      11	младший бит - сумма

Полусумматор: функция логической суммы:

    SUM |
    A+B |   0       1       2
    ----+------------------------
     0  |   0       1       2
     1  |   1       2       0
     2  |   2       0       1	только младший бит - сумма

    SUM |
    A/B |	0	i	1
    ----+------------------------
     0  |   0	i	1
     i  |   i	1	0
     1  |   1	0	i

    --+----------
      | -  0  +
    --+----------   арифметика {0,1,2}
    - | -  0  +
    0 | 0  +  -
    + | +  -  0
    --+----------

    --+----------
      | -  0  +
    --+----------   арифметика {-,0,+}
    - | +  -  0
    0 | -  0  +
    + | 0  +  -
    --+----------

Полусумматор: функция переноса:

    CARRY
    A+B |   0       1       2
    ----+------------------------
     0  |   0       0       0
     1  |   0       0       1	только старший бит - перенос
     2  |   0       1       1

    CARRY
    A/B |	0	i	1
    ----+------------------------
    0   |   0	0	0
    i   |   0	0	i
    1   |   0 	i	i

    --+----------
      | -  0  +
    --+----------  Арифметика {0,1,2}
    - | -  -  -
    0 | -  -  0
    + | -  0  0
    --+----------

    --+----------
      | -  0  +
    --+----------  Арифметика {-,0,+}
    - | -  0  0
    0 | 0  0  0
    + | 0  0  +
    --+----------

Умножение:

Для {0,1,2}:

    A*B |   0       1       2
    ----+------------------------
     0  |   0       0       0
     1  |   0       1       2
     2  |   0       2      11

    MUL
    A*B |   0       1       2
    ----+------------------------
     0  |   0       0       0
     1  |   0       1       2	только младший бит
     2  |   0       2       1

    CARRY
    A*B |	0	i	1
    ----+------------------------
    0   |   0	0	0
    i   |   0	0	0       только старший бит - перенос
    1   |   0 	0	1

Для {-,0,+} все сильно проще:
и никаких переносов.

  Умножение
    --+----------
      | -  0  +
    --+----------
    - | +  0  -
    0 | 0  0  0
    + | -  0  +
    --+----------

  Дополнительный код (троичный)

Дополнительный код имеет смысл только для системы {0,1,2},
потому что система {-,0,+} может представлять отрицательные числа
естественным способом.

Соответсвенно для {0,1,2} отрицательные числа удобно представлять
в дополнительном коде (дополнение до 3)
тогда можно использовать сумматоры для вычитания:
    A - B = A + (-B)

-Х в дополнительном коде определяется как и в двоичном случае
(NOT(X) дополняет до 2, прибавлением единицы дополняем до 3)

    -X = NOT(X) + 1		в арифметическом смысле (1)
                т.е цифры:

Получаем функцию NEG (она же обмен i и 1):
(В двоичном случае - что NOT что NEG одинаковые, но в троичном они
 расслаиваются на две разные функции.

    X  | NEG
    ---+----
    0  | 0
    i  | 1
    1  | i

Проверка:
    X + (-X) = 0

    X  -X | X + (-X)
    ------+---------
    0  0  |   0
    i  1  |   0
    1  i  |   0

Все верно.

Особенно хочется обратить внимание что -X арифметическая функция и поэтому
она затрагивает все разряды числа:

Пример:
    Число    = 0i0
    NOT(1i)  = 1i1
    NEG(1i)  = 1i1 + 00i = 1i0 + 0i0 = 110
                 |     |          ^
                 +-----+          |
                       |          |
                       +----------+

    Проверка:  0i0 + 110 = 100 + i00 = (1)000

Законы троичной логики:

Расмотрим еще некоторые функции
{ -, 0, + }

  Сложение по модулю
    --+----------
      | -  0  +
    --+----------
    - | +  -  0
    0 | -  0  +
    + | 0  +  -
    --+----------

  Перенос в сложении по модулю
    --+----------
      | -  0  +
    --+----------
    - | -  0  0
    0 | 0  0  0
    + | 0  0  +
    --+----------

  Сложение с насышением
    --+----------
      | -  0  +
    --+----------
    - | -  -  0
    0 | -  0  +
    + | 0  +  +
    --+----------

  Функция Webb
    --+----------
      | -  0  +
    --+----------
    - | 0  +  -
    0 | +  +  -
    + | -  -  -
    --+----------

   Тождество (строгоe)
    --+----------
      | -  0  +
    --+----------
    - | +  -  -
    0 | -  +  -
    + | -  -  +
    --+----------

   Тождество (weak)
    --+----------
      | -  0  +
    --+----------
    - | +  0  -
    0 | 0  0  0      в общем как умножение
    + | -  0  +
    --+----------

    Коньюнкция Лукашевича (сильная)
    --+----------
      | -  0  +
    --+----------
    - | -  -  -
    0 | -  -  0
    + | -  0  +
    --+----------

    Импликация Лукашевича
    --+----------
      | -  0  +
    --+----------
    - | +  0  -
    0 | +  +  0
    + | +  +  +
    --+----------

     Коньюнкция Клини
    --+----------
      | -  0  +
    --+----------
    - | -  0  -
    0 | 0  0  0
    + | -  0  +
    --+----------

     Импликация Клини
    --+----------
      | -  0  +
    --+----------
    - | +  +  +
    0 | 0  0  0
    + | -  0  +
    --+----------

     Интуиционистская импликация Геделя
    --+----------
      | -  0  +
    --+----------
    - | +  -  -
    0 | +  +  0
    + | +  +  +
    --+----------

      Материальная импликация
    --+----------
      | -  0  +
    --+----------
    - | +  0  -
    0 | +  0  0
    + | +  +  +
    --+----------

      Функция следования Брусенцова
    --+----------
      | -  0  +
    --+----------
    - | +  0  -
    0 | 0  0  0
    + | 0  0  +
    --+----------

  Info

Web http://www.trinary.cc/ Сайт посвященный разработке троичных устройств

Search Trinary Logic


2.11.2. ЧЕТВЕРИЧНАЯ ЛОГИКА

Четверичная логика:

    ----------------------
    0	нет
    j	не может быть
    i	может быть
    1	да
    ----------------------

Диаграмма Венна для функций двух операндов.
Каждый операнд это 3 круга. Внутри внутреннего операнд равен 1, затем между
кругами он равен I и J соответсвенно, снаружи внешнего равен нулю.

Значения:
    0	сплошной белый
    j	сплошной желтый
    i	сплошной зеленый
    1	штрихованный черный

На диаграмме желтым цветом выделены зоны которые (как и в троичной логики
имеют 2 видимые несмежные симметричные зоны на диаграмме.

Правила все те же:
  X AND Y = MIN(X,Y)
  X OR  Y = MAX(X,Y)

----------------------------
XY	X#	AND	OR
----------------------------
00	1       0	0
0j      1       0       j
0i      1       0       i
01      1       0       1
j0      i       0       j
jj      i       j       j
ji      i       j       i
j1      i       j       1
i0      j       0       i
ij      j       j       i
ii      j       i       i
i1      j       i       1
10      0       0       1
1j      0       j       1
1i      0       i       1
11      0       1       1
----------------------------

AND:

OR:

  Четверичная комплементарная логика

    -----------------------
    0	нет
    j	не может быть
    i	может быть
    1	да
    -----------------------

Отличается от обычной четверичной логики свойствами комплиментарности:
    0+1=1	i+j=1
    0*1=0	i*j=0

(На самом деле эта та же четверичная логика, но в качестве функций
 AND и OR выбраны специальные варианты комплемертарныго MAX и MIN.

----------------------------
XY	X#	CAND	COR
----------------------------
00	1       0	0
0j      1       0       j
0i      1       0       i
01      1       0       1
j0      i       0       j
jj      i       j       j
ji      i       0       1
j1      i       j       1
i0      j       0       1
ij      j       0       1
ii      j       i       i
i1      j       i       1
10      0       0       1
1j      0       j       1
1i      0       i       1
11      0       1       1
----------------------------

CAND:

COR:

  Базис

Все тоже самое - функция Уэбба

    W(X,Y) =  X + 1, если X == Y
          0    , если X != Y

    X Y  | F
    -----+---
    0 0  | j
    0 j  | 0
    0 i  | 0
    0 1  | 0
    j 0  | 0
    j j  | i
    j i  | 0
    j 1  | 0
    i 0  | 0
    i j  | 0
    i i  | 1
    i 1  | 0
    1 0  | 0
    1 j  | 0
    1 i  | 0
    1 1  | 0


2.12. КОЛИЧЕСТВО ЛОГИК

Правила:
    0 < 1		(если наоборот то то же самое - пофигу как называть)
    i < j < k	(неопределенности)
    сначала заполняем значения, потом неопределенности сколько влезет

Двоичная:
     ------------------------------------
     младш старш	(1 логика)
     ------------------------------------
    0  1		без вариантов
     ------------------------------------

Троичные:
     ------------------------------------
     младш   старш      (3 логики)
     ------------------------------------
    i  0  1
    0  i  1		обычно используем ее (более логичная)
    0  1  i
     ------------------------------------

Четверичные:
     ------------------------------------
     младш     старш    (6 логик)
     ------------------------------------
        i  j  0  1
        i  0  j  1
    i  0  1  j
    0  i  j  1	обычно используем ее
    0  i  1  j
    0  1  i  j
     ------------------------------------

Пятиричные:
     ------------------------------------
     младш     старш      (10 логик)
     ------------------------------------
    i  j  k  0  1          --+
    i  j  0  k  1            |
    i  j  0  1  k            | 6 как в 4ной
    i  0  j  k  1            |
    i  0  j  1  k            |
    i  0  1  j  k		-+
    0  i  j  k  1		-+
    0  i  j  1  k            | 3 как в 3ной
    0  i  1  j  k           -+
    0  1  i  j  k		 | 1 как в 2ной
     ------------------------------------

А в Шестиричной будет: 10 + 6 + 3 + 1 = 20 логик.

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


2.13. ЖЕНСКАЯ ЛОГИКА

В каждой шутке есть доля шутки:

-Не хотите учить логику?
-Будем учить женскую логику
    Женская логика состоит из 3 основных логических элементов:
        1. НЕ
        2. Все равно НЕ
        3. Чего бы ты не сказал, все равно НЕ
(Т.е. женская логика - типичный пример фрактальной логики).

Женская логика - троичная логика логика с одним высокоимпедансным состоянием.
     Состояния:
        1. Дам
        2. Не дам
        3. Дам но с большим сопротивлением
кстати для типичного MOS транзистора разница между (1) и (3)
состовляет 10^6 раз :)

Эссе о женской логике.

Как правило у женщин женская логика (исключений менее 1% особей).
Если разговор об этом 1% то Вам не сюда.
Чтобы спорить с конкретным экземпляром было легко надо вычислить  связи между
элементами в конкретном экземпляре:

Как известно женская логика основывается на 3х логических элементах:
     1.НЕ
     2.ВСЕ РАВНО НЕ
     3.ЧТО БЫ ТЫ НЕ СКАЗАЛ, ВСЕ РАВНО НЕ...

Соответственно результаты внешнего воздействия зависят от связей между этими
элементами. Кстати элементы памяти там тоже присутствуют, поэтому
описать чисто комбинационной схемой не получится. В общем получаем DFA.
Лично Я склоняюсь к мысле что все таки это скорее автомат Мура, чем автомат Милли,
потому что выходы все таки зависят от состояния больше чем от внешних воздействий.
Для изучения связей между элементами рекомендуется составить каталог типовых реакций.

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


2.14. ДИАГРАММЫ ВЕННА

  Диаграммы Венна

Джон Венн (John Venn) (1834-1923)

Вообще говоря диаграммы Венна служат для работы с множествами:

В случае когда число переменных больше 3 круги не помогают:

Можно переходить в 3х мерное пространство - пользоватся шарами, но
для случая 5 - уже надо будет идти в гиперпространство.

Альтернатива - переходить к эллипсам.

Пример диаграммы Венна для 5 переменных:

  Диаграммы Джонстона

Вариант который мы использовали для показа двоичной логики
(где у нас на диаграмме Венна закрашена зона для 1, и не закрашена для 0)
называется диаграмма Джонстона (Johnston):

  Диаграммы Эдвардса

Диаграммы Эдвардса (Antony William Fairbank Edwards) - один из вариантов Диаграмм
Венна:
(во всяком случае с ним удобней работать при большом числе переменных).
(потому что наглядно видно где-какая зона - а в случае диаграммы Венна надо еще
думать и смотреть все эллипсы).

для 3 переменных:

для 4 переменных:

для 5 переменных:

для 6 переменных:


2.15. НЕМНОГО КОМБИНАТОРИКИ

Давайте посмотрим сколько минтермов различных рангов существует.
Если нам надо взять k предметов из N - то количество перестановок равно:

Сочетания из n объектов по k:

               n!
    С(n,k) = ---------------
            (n-k)! * k!

    где n! - факториал
    n! = n * (n-1) * (n-2) * ... * 2 * 1
    1! = 1
    0! = 1

Другая форма записи, практикуемая в американской литературе:

      n
    (   )  = C(n,k)
      k

Свойства:

    С(n,k) = C(n, n-k)
    C(n,k) = C(n-1, k-1) + C(n-1, k)
    C(n,0) + C(1,0) + ... + C(n,n) = 2^n

     n     n-1     n-1
    ( ) = (   ) + (   )
     r     r-1      r

              r
             ---
     m+n     \     m    n
    (   ) =  /    ( ) (   )
      r      ---   k   r-k
             k=0

              n
                 ---
     2n      \     n  2
    (  )  =  /    ( )
     n       ---   k
                 k=0

  Биномальные коэффициенты

Треугольник Паскаля:
                                                        n
            1   				0
             1     1                            1
          1     2     1                         2
                1    3     3     1                      3
         1    4     6    4      1                   4
      1    5    10    10    5      1                5
       1    6    15     20   15     6     1             6
    1    7    21    35     35   21     7     1          7
 1    8    28    56     70   56    28     8     1       8

  Мультиномиальные коэффициенты:

Для трех переменных:

[1,0,0] = 1

[2,0,0] = 1
[1,1,0] = 2

[3,0,0] = 1
[2,1,0] = 3
[1,1,1] = 6

[4,0,0] = 1
[3,1,0] = 4
[2,2,0] = 6
[2,1,1] = 12

[5,0,0] = 1
[4,1,0] = 5
[3,2,0] = 10
[3,1,1] = 20
[2,2,1] = 30

[6,0,0] = 1
[5,1,0] = 6
[4,2,0] = 15
[4,1,1] = 30
[3,3,0] = 20
[3,2,1] = 60
[2,2,2] = 90

[7,0,0] = 1
[6,1,0] = 7
[5,2,0] = 21
[5,1,1] = 42
[4,3,0] = 35
[4,2,1] = 105
[3,3,1] = 140

Для четырех переменных:

[1,0,0,0] = 1

[2,0,0,0] = 1
[1,1,0,0] = 2

[3,0,0,0] = 1
[2,1,0,0] = 3
[1,1,1,0] = 6

[4,0,0,0] = 1
[3,1,0,0] = 4
[2,2,0,0] = 6
[2,1,1,0] = 12
[1,1,1,1] = 24

[5,0,0,0] = 1
[4,1,0,0] = 5
[3,2,0,0] = 10
[3,1,1,0] = 20
[2,2,1,0] = 30
[2,1,1,1] = 60

[6,0,0,0] = 1
[5,1,0,0] = 6
[4,2,0,0] = 15
[4,1,1,0] = 30
[3,3,0,0] = 20
[3,2,1,0] = 60
[3,1,1,1] = 120
[2,2,2,0] = 90
[2,2,1,1] = 180

  Сочетания

  2

Пример сочетаний:

для числа переменных N=2:

    ---------------------
    1	2	1
    ---------------------
    XX	X-	--
        -X
    ---------------------

  3

для числа переменных N=3:
    --------------------------
         1	 3	3	1
    --------------------------
    XXX	XX-	X--    ---
        X-X     -X-
        -XX     --X
    --------------------------

  4

для числа переменных N=4:

    ------------------------------------
    1	4	6	4	1
    ------------------------------------
    XXXX	XXX-	XX--	X---	----
        XX-X    X-X-    -X--
        X-XX    -XX-    --X-
        -XXX    X--X    ---X
            -X-X
            --XX
    ------------------------------------

  5

для числа переменных N=5:
    ---------------------------------------------
    1	5	10	10	5	1
    ---------------------------------------------
    XXXXX	XXXX-	XXX--	---XX	----X	-----
        XXX-X   XX-X-   --X-X   ---X-
        XX-XX   X-XX-   -X--X   --X--
        X-XXX   -XXX-   X---X   -X---
        -XXXX   XX--X   --XX-   X----
            X-X-X   -X-X-
            -XX-X   X--X-
            X--XX   -XX--
            -X-XX   X-X--
            --XXX   XX---
    ---------------------------------------------

  6

для числа переменных N=6:
    ------------------------------------------------------
    1	6	15	20	15	6	1
    ------------------------------------------------------
    XXXXXX  XXXXX-	XXXX--	XXX---	----XX	-----X	------
        XXXX-X  XXX-X-  XX-X--  ---X-X  ----X-
        XXX-XX  XX-XX-  X-XX--  --X--X  ---X--
        XX-XXX  X-XXX-  -XXX--  -X---X  --X---
        X-XXXX  -XXXX-  XX--X-  X----X  -X----
        -XXXXX  XXX--X  X-X-X-  ---XX-  X-----
            XX-X-X  -XX-X-  --X-X-
            X-XX-X  X--XX-  -X--X-
            -XXX-X  -X-XX-  X---X-
            XX--XX  --XXX-  --XX--
            X-X-XX  XX---X  -X-X--
            -XX-XX  X-X--X  X--X--
            X--XXX  -XX--X  -XX---
            -X-XXX  X--X-X  X-X---
            --XXXX  -X-X-X  XX----
                --XX-X
                X---XX
                -X--XX
                --X-XX
                ---XXX
    ------------------------------------------------------

  7

для числа переменных N=7:
 -----------------------------------------------------------------
1	7	21	35	35	21	7	1
 -----------------------------------------------------------------
XXXXXXX	XXXXXX-	XXXXX--	XXXX---
    XXXXX-X XXXX-X- XXX-X--
    XXXX-XX XXX-XX- XX-XX--
    XXX-XXX XX-XXX- X-XXX--
    XX-XXXX X-XXXX- -XXXX--
    X-XXXXX -XXXXX- XXX--X-
    -XXXXXX XXXX--X XX-X-X-
        XXX-X-X X-XX-X-
        XX-XX-X -XXX-X-
        X-XXX-X XX--XX-
        -XXXX-X X-X-XX-
        XXX--XX -XX-XX-
        XX-X-XX X--XXX-
        X-XX-XX -X-XXX-
        -XXX-XX --XXXX-
        XX--XXX XXX---X
        X-X-XXX XX-X--X
        -XX-XXX X-XX--X
        X--XXXX -XXX--X
        -X-XXXX XX--X-X
        --XXXXX X-X-X-X
            -XX-X-X
            X--XX-X
            -X-XX-X
            --XXX-X
            XX---XX
            X-X--XX
            -XX--XX
            X--X-XX
            -X-X-XX
            --XX-XX
            X---XXX
            -X--XXX
            --X-XXX
            ---XXXX
 -----------------------------------------------------------------

  8

Каким образом считать двойные сочетания.

Но для каждой уникальной перестановки возможно 2^R вариантов Минтермов.

примеры:

    ------------------------------------------------------
    2	3	2	3		ранг минтерма
    XX-	X-XX	X--X	X--X-X-		перестановка
    ------------------------------------------------------
    00-     0-00    0--0    0--0-0-		варианты
    01-     0-01    0--1    0--0-1-
    10-     0-10    1--0    0--1-0-
    11-     0-11    1--1    0--1-1-
            1-00            1--0-0-
            1-01            1--0-1-
        1-10            1--1-0-
        1-11            1--1-1-
    ------------------------------------------------------

Таким образом:
Количество переменных = N
Количество минтермов ранга R = С(N,R) * 2^R

Пример для N=3
    ранга 3:	1 * 2^3  = 1 * 8 = 8
    ранга 2:	3 * 2^2  = 3 * 4 = 12
    ранга 1:	3 * 2^1  = 3 * 2 = 6
    ранга 0:	1 * 2^0  = 1 * 1 = 1

Например для N=4:
    ранга 4:	1 * 2^4  = 1 * 16 = 16
    ранга 3:	4 * 2^3  = 4 * 8  = 32
    ранга 2:	6 * 2^2  = 6 * 4  = 24
    ранга 1:	4 * 2^1  = 4 * 2  = 8
    ранга 0:	1 * 2^0  = 1 * 1  = 1

Пример для N=5
    ранга 5:	1 * 2^5  =  1 * 32 = 32
    ранга 4:	5 * 2^4  =  5 * 16 = 80
    ранга 3:       10 * 2^3  = 10 * 8  = 80
    ранга 2:       10 * 2^2  = 10 * 4  = 40
    ранга 1:	5 * 2^1  =  5 * 2  = 10
    ранга 0:	1 * 2^0  =  1 * 1  = 1

Для N=6:
    ранга 6:	1 * 2^6  =  1 * 64  = 64
    ранга 5:	6 * 2^5  =  6 * 32  = 192
    ранга 4:       15 * 2^4  = 15 * 16  = 240
    ранга 3:       20 * 2^3  = 20 * 8   = 160
    ранга 2:       15 * 2^2  = 15 * 4   = 60
    ранга 1:	6 * 2^1  =  6 * 2   = 12
    ранга 0:	1 * 2^0  =  1 * 1   = 1

  Геометрический смысл биномальных коэффициентов

Собственно говоря строки треугольника Паскаля - это еще и коэффициенты
при членах разложения (x + 1)^N

    (x + 1)^0  = 1
    (x + 1)^1  = x + 1
    (x + 1)^2  = x^2 + 2*x + 1
    (x + 1)^3  = x^3 + 3*x^2 + 3*x + 1

Геометрический смысл:

  Перестановки

Перестановки из n объектов по r:

                       n!
    P(n,r) = --------------
            (n-r)!

  1

      -----
    1
         1
      -----

  2

e:

      ---------
    1  2
        1  2
      ---------

      ---------
    1  2
        2  1
      ---------

  3

2 из 3:
    Сочетания	Перестановки
    порядок		порядок
    неважен		важен
    (12)		[12] [21]
    (13)		[13] [31]
    (23)		[23] [32]

      ----------
    1 2 3
    1 2 3
      ---------

      ----------
    1 2 3
    3 1 2
      ----------

      ----------
    1 2 3
    2 3 1
      ----------

      ----------
    1 2 3
    1 3 2
      ----------

      ----------
    1 2 3
    2 1 3
      ----------

      ----------
    1 2 3
    3 2 1
      ----------

  4

2 из 4:
    Сочетания		Перестановки
    порядок			порядок
    неважен			важен
    (12)                    [12]	[21]
    (13)	(23)            [13]	[31]	[23]	[32]
    (14)    (24)	(34)    [14]    [41] 	[24]	[42]	[34]	[43]

3 из 4:
    класс 0-0-1
    (123)
    (234)
    (341) = (134)
    (412) = (124)

    все упорядоченно:
    Сочетания	Перестановки
    порядок		порядок
    неважен		важен
    123		[123] [132] [213] [231] [312] [321]
    124		[124] [142] [214] [241] [412] [421]
    134		[134] [143] [314] [341] [413] [431]
    234		[234] [243] [324] [342] [423] [432]

4 из 4:

Тождество
       ---------
    1 2 3 4
    1 2 3 4
       ---------

Вращение -90

       ---------
    1 2 3 4
    4 1 2 3
       ---------

Вращение -180

       ---------
    1 2 3 4
    3 4 1 2
       ---------

Вращение -270

       ---------
    1 2 3 4
    2 3 4 1
       ---------

Отражение через вертикаль

       ---------
    1 2 3 4
    2 1 4 3
       ---------

Отражение через горизонталь
       ---------
    1 2 3 4
    4 3 2 1
       ---------

Отражение LD-RU диоганаль

       ---------
    1 2 3 4
    3 2 1 4
       ---------

Отражение LU-RD диагональ

       ---------
    1 2 3 4
    1 4 3 2
       ---------

Отражение через центр

       ---------
    1 2 3 4
    3 4 1 2
       ---------
оно в данном случае экивалентно повороту на 180'

Вырожденный случай - обмен пары
Таких случаев 6 - потому что 6 пар.

       ---------
    1 2 3 4         (1 - 2)
    2 1 3 4
       ---------

       ---------
    1 2 3 4         (1 - 3)
    3 2 1 4
       ---------

       ---------
    1 2 3 4         (1 - 4)
    4 2 3 1
       ---------

       ---------
    1 2 3 4 	(2 - 3)
        1 3 2 4
       ---------

       ---------
    1 2 3 4 	(2 - 4)
    1 4 3 2
       ---------

       ---------
    1 2 3 4		(3 - 4)
    1 2 4 3
       ---------

Вырожденный случай - вращение трешки вправо
Таких случаев 4, потому что 4 трешки

       ---------
    1 2 3 4         [123]
    3 1 2 4
       ---------

       ---------
    1 2 3 4         [124]
    4 1 3 2
       ---------

       ---------
    1 2 3 4         [134]
    4 2 1 3
       ---------

       ---------
    1 2 3 4         [234]
        1 4 2 3
       ---------

Вырожденный случай - вращение трешки влево
Таких случаев 4, потому что 4 трешки

       ---------
    1 2 3 4 	[123]
    2 3 1 4
       ---------

       ---------
    1 2 3 4         [124]
    2 4 3 1
       ---------

       ---------
    1 2 3 4 	[134]
    3 2 4 1
       ---------

       ---------
    1 2 3 4 	[234]
    1 3 4 2
       ---------

Вращение (только по другим переменным)

       ----------
    1 2 3 4
    2 4 1 3
       ----------

тоже но в обратную сторону

       ----------
    1 2 3 4
    3 1 4 2
       ----------

Еще одно вращение по другим переменным

       ----------
    1 2 3 4
    4 3 1 2
       ----------

тоже но в обратную стророну

       ----------
    1 2 3 4
    3 4 2 1
       ----------

Всего перестановок 24 (мы их все описали базируясь на геометрическом смысле).
Теперь полный список:

    -------------------------------------------
    1 2 3 4	  e
    1 2 4 3   обмен 3-4
    1 3 2 4   обмен 2-3
    1 3 4 2   вращение [234] влево
    1 4 2 3   вращение [234] вправо
    1 4 3 2   отражение по оси 1-3, обмен 2-4
    2 1 3 4   обмен 1-2
    2 1 4 3	  отражение вертикаль
    2 3 1 4   вращение [123] влево
    2 3 4 1	  поворот -270/+90
    2 4 1 3   вращение вправо
    2 4 3 1   вращение [124] влево
    3 1 2 4   вращение [123] вправо
    3 1 4 2   вращение
    3 2 1 4	  отражение по оси 2-4, обмен 1-3
    3 2 4 1   вращение [134] влево
    3 4 1 2   поворот -180/+180, отражение через центр
    3 4 2 1   вращение
    4 1 2 3	  поворот -90/+270
    4 1 3 2   вращение [124] вправо
    4 2 1 3   вращение [134] вправо
    4 2 3 1   обмен 1-4
    4 3 1 2   вращение
    4 3 2 1	  отражение горизонталь
    -------------------------------------------

  5

И 4 других аналогичных

  6

  Разбиения

     --------------------------
      Число    Число разбиений
     --------------------------
    1	1
    2	2
    3	3
    4	5
    5	7
    6	11
    7	15
    8	22
    9	30
    10	42
     --------------------------

Диаграммы Юнга.

[1]

[2]
[1,1]

[3]
[2,1]
[1,1,1]

[4]
[3,1]
[2,2]
[2,1,1]
[1,1,1,1]

[5]
[4,1]
[3,2]
[3,1,1]
[2,2,1]
[2,1,1,1]
[1,1,1,1,1]

[6]
[5,1]
[4,2]
[4,1,1]
[3,3]
[3,2,1]
[3,1,1,1]
[2,2,2]
[2,2,1,1]
[2,1,1,1,1]
[1,1,1,1,1,1]

[7]
[6,1]
[5,2]
[5,1,1]
[4,3]
[4,2,1]
[4,1,1,1]
[3,3,1]
[3,2,2]
[3,2,1,1]
[3,1,1,1,1]
[2,2,2,1]
[2,2,1,1,1]
[2,1,1,1,1,1]
[1,1,1,1,1,1,1]

[8]
[7,1]
[6,2]
[6,1,1]
[5,3]
[5,2,1]
[5,1,1,1]
[4,4]
[4,3,1]
[4,2,2]
[4,2,1,1]
[4,1,1,1,1]
[3,3,2]
[3,3,1,1]
[3,2,2,1]
[3,2,1,1,1]
[3,1,1,1,1,1]
[2,2,2,2]
[2,2,2,1,1]
[2,2,1,1,1,1]
[2,1,1,1,1,1,1]
[1,1,1,1,1,1,1,1]

Мультиномальные коэфициенты:
Предположим что у нас 4 переменных, и 7 степень,
нам подходят только те разбиения в которых число партиций не превышает 4.
то есть

              число
              партиций
[7]			1 - OK
[6,1]                   2 - OK
[5,2]                   2 - OK
[5,1,1]                 3 - OK
[4,3]                   2 - OK
[4,2,1]                 3 - OK
[4,1,1,1]               4 - OK
[3,3,1]                 3 - OK
[3,2,2]                 3 - OK
[3,2,1,1]               4 - OK
[3,1,1,1,1]             5 - NONE
[2,2,2,1]               4 - OK
[2,2,1,1,1]             5 - NONE
[2,1,1,1,1,1]           6 - NONE
[1,1,1,1,1,1,1]         7 - NONE

  Диаграммы Юнга и перестановки

столбик из двух - это обмен

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

Тождество - оно одно

    1234

    ----------
     1 2 3 4
     1 2 3 4
    ----------

Обмен пары.
Всего существует 6 вариантов:

    123 		123
    4                4

    ----------	----------
     1 2 3 4         1 2 3 4
     4 2 3 1         1 4 3 2
        ----------      ----------

    124		124
    3                3
    ----------	----------
     1 2 3 4         1 2 3 4
     3 2 1 4	 1 3 2 4
        ----------      ----------

    134 		123
    2                 4
    ----------	----------
     1 2 3 4         1 2 3 4
     2 1 3 4	 1 2 4 3
    ----------	----------

Обмен двух пар:

    12		13		12
    34              24              43

    ----------	----------	----------
     1 2 3 4         1 2 3 4         1 2 3 4
     3 4 1 2	 2 1 4 3	 4 3 2 1
    ----------	----------	----------

Всего есть 3 варианта - двух пар.

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

      41	     31		23	   43
          2          4          4          1
          3          2          1          2
     ---------- ---------- ---------- ----------
      1 2 3 4    1 2 3 4    1 2 3 4    1 2 3 4
      1 4 2 3    1 3 4 2	2 4 3 1    4 1 3 2
     ---------- ---------- ---------- ----------

      32 	     42		24	   34
      4          1          3          1
      1          3          1          2
     ---------- ---------- ---------- ----------
      1 2 3 4    1 2 3 4    1 2 3 4    1 2 3 4
      3 2 4 1    4 2 1 3	2 3 1 4	   3 1 2 4
     ---------- ---------- ---------- ----------

Вращения

    2		4
    3               1
    4               2
    1               3
    ----------	----------
     1 2 3 4         1 2 3 4
     2 3 4 1	 4 1 2 3
    ----------	----------
    (1234)~>          <~(1234)

    2	    3	       3	  4
    4           1          4          3
    1           4          2          1
    3           2          1          2
    ---------- ---------- ---------- ----------
     1 2 3 4    1 2 3 4    1 2 3 4    1 2 3 4
     2 4 1 3    3 1 4 2    3 4 2 1    4 3 1 2
    ---------- ---------- ---------- ----------
    (1243)~>     <~(1243)   (1324)~>     <~(1324)

Почему вращений всего 6?
    1 фиксируем на 1й позиции тогда возможные варианты:

        1.234
        1.243
        1.324
        1.342 = - 1.243	 тоже но вращение в другую сторону
        1.423 = - 1.324	 тоже но вращение в другую сторону
        1.432 = - 1.234  тоже но вращение в другую сторону

    1234 left  = 2341 = 3412 right
    1234 right = 4123 = 3412 left

    1243 left  = 2431 = 4312 right
    1243 right = 3124 = 4312 left

    1324 left  = 3241 = 2413 right
    1324 right = 4132 = 2413 left

  Композиции

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

[1]

  2

[2,0]
[1,1]
[0,2]

  3

[3,0,0]
[2,1,0]
[2,0,1]
[1,2,0]
[1,1,1]
[1,0,2]
[0,3,0]
[0,2,1]
[0,1,2]
[0,0,3]

[3,0,0]

[2,1,0]

[2,0,1]

[1,2,0]

[1,1,1]

[1,0,2]

[0,3,0]

[0,2,1]

[0,1,2]

[0,0,3]

  4

[4,0,0,0]
[3,1,0,0]
[3,0,1,0]
[3,0,0,1]
[2,2,0,0]
[2,0,2,0]
[2,0,0,2]
[2,1,1,0]
[2,1,0,1]
[2,0,1,1]
[1,3,0,0]
[1,2,1,0]
[1,2,0,1]
[1,1,1,1]
[1,0,3,0]
[1,0,2,1]
[1,0,1,2]
[0,4,0,0]
[0,3,1,0]
[0,3,0,1]
[0,2,2,0]
[0,2,1,1]
[0,2,0,2]
[0,1,3,0]
[0,1,2,1]
[0,1,1,2]
[0,1,0,3]
[0,0,4,0]
[0,0,3,1]
[0,0,2,2]
[0,0,1,3]
[0,0,0,4]

  Числа Каталана

           (2n)!
Cat(n) = ----------
          (n+1)! n!

    n	Cat(n)
    0	1
    1	1
    2	2
    3	5
    4	14
    5	42
    6	132
    7	429
    8	1430
    9	4862
    10	16796
    11	58786
    12	208012
    13	742900
    14	2674440
    15	9694845
    16	35357670
    17	129644790
    18	477638700
    19	1767263190

Числа Каталана - количество разбиений выпуклых многоугольников с n+2 сторонами
n-1 непересекающимися диоганалями.

Числа каталана - это число двоичных деревьев с N узлами


2.16. ФОРМАЛЬНАЯ ЛОГИКА

  Modus Ponendo Ponens

        P -> Q
        P
        -------
        Q

  Силлогизм

        P -> Q
        Q -> R
        -------
        P -> R

  Modus Tollendo Tollens

        P -> Q
        ~Q
        ------
        ~P

  Расширение

        P
        ------
        P + Q

  Специализация

        P * Q
        Q
        -----
        P

  Конъюнкция

        P
        Q
        -----
        P * Q

  Выбор

        P
        P -> (R + S)
        R -> Q
        S -> Q
        -----------
        Q

  Исключающий выбор

Верно только для непересекающихся P и Q

        P + Q
        P -> (R + ~R)
        -------------
        Q

  Reductio ad Absurdum

Сведение к абсурду
(доказательство от противного)

        ~P -> (R + ~R)
        --------------
        P

  Modus Ponendo Tollens

Верно только для непересекающихся A и B

        ~(A + B)
        A
        --------
        ~B

  Modus Tollendo Ponens

        A + B
        ~A
        -------
        B

  Доказательство

Докажем какой нибудь из принципов формальной логики
например силлогизм

        P -> Q
        Q -> R
        -------
        P -> R

Запишем правило словами:
    Если P->Q верно и Q->R верно, то P->R тоже верно

    ---------------------------------------------
    P	Q	S	P->Q	Q->S	P->S
    ---------------------------------------------
    0	0	0	1*	1*	1*
    0	0	1	1*	1*	1*
    0	1	0       1       0       1
    0	1	1       1*      1*      1*
    1	0	0       0       1       0
    1	0	1       0       1       1
    1	1	0       1       0       0
    1	1	1       1*      1*      1*
    ---------------------------------------------
Видем что все правильно

  Связи между двумя объектами

Некоторые X есть Y

Все X есть Y

Все Y есть X

Никакие из X не есть Y

X это Y
(все X это Y, все Y это X)

  Диаграммы Льюиса Кэрола

Тут мы ее немного модифицировали

  Связи между тремя объектами


2.17. ПЕРЕКЛЮЧАТЕЛЬНАЯ ЛОГИКА

THIS SECTION IS UNDER CONSTRUCTION

  AND

F = A*B

  OR

F = A+B

  Пример

F = A + BC

  Мостовая логика

F = AB + CD + AED + CEB

  XOR


3. СИСТЕМЫ СЧИСЛЕНИЯ

---------------------------------------------
Эпиграф:
    Ей было тысяча сто лет
    Она в сто первый класс ходила
    С собою по сто книг носила
    Все это правда, а не бред
    Когда шурша десятком ног
    Она шагала по дороге
    За ней бежал один щенок
    С одним хвостом
    Зато стоногий
    Она ловила каждый звук
    Своими десятью ушами
    И десять загорелых рук
    Портфель и поводок держали
    И десять темно синих глаз
    Рассматривали мир привычно
    Но станет все совсем обычным
    Когда поймете наш рассказ
        Журнал "Квант" прошлый век.
----------------------------------------------

Def
===
Система счисления - способ записи (изображения) чисел.

Def
===
Цифра - один из символов при помощи которых записывается число.

              Системы счисления
                /               \
           Позиционные      Непозиционные
         /      |      \
Традиционные Смешанные  Нетрадиционные
  P-ричные    P-Q-           |
                          Сбалансированные

Позиционные - вклад цифры зависит от ее позиции
Непозиционные - вклад чифры зависит от самой цифры
        (как правило непозиционные системы - алфавитные).

Def
===
Позиционная система счисления - система счисления, в которой числовое значение
каждой цифры зависит от номера ее позиции в последовательности цифр,
представляющих число.

Def
===
Непозиционная система счисления - система счисления в котором цифре всегда
соответствует определенное значение не зависимо от местоположения в записи числа.

Def
===
Базис позиционной системы счисления - последовательность чисел задающая вес каждого
разряда.

Пример для 10: 1, 10, 100, 1000 итд

Def
===
Знаменатель P геометрической прогрессии образующей базис позиционной системы
счисления называется основанием системы счисления.


3.1. НЕПОЗИЦИОННЫЕ СИСТЕМЫ СЧИСЛЕНИЯ

  Историческая роль

10 пальцев на руках

Семь - это уже много
    ---------------------------------
    Семеро одного не ждут
    У семи нянек дитя без глаза
    Семь раз отмерь - один раз отрежь
    ---------------------------------

12 фаланг пальцев на руке

явно 24 часа в сутках вылезли отсюда.

А отсюда вылезла система счисления с основанием 60:

  Единичная

Система счисления: Единичная
каждый предмет это палка

    |||		3

    |||||		5

    ||||||		6

    || + ||| = |||||

  Римская

Римские цифры

       --------------
    I	1
    V	5
    X	10
    L	50
    C	100
    D	500
    M	1000
       --------------

Непозиционная система с дополнительными правилами.

Правила:
    Значение числа равно
    1) сумме значений идущих подряд одинаковых цифр
    2) разности двух цифр если слева от большей стоит меньшая
       (причем левая чифра может быть меньше только на порядок)
        т.е.
        для	V  и Х  - I
        для	L  и C  - X
        для	D  и M  - C
    3) сумма значений цифр и групп не вошедших в (1) и (2)

    I	1
    II	2
    III	3
    IV	4
    V	5
    VI	6
    VII	7
    VIII	8
    IX	9
    X	10

    XC		90
    XD		490
    MCMLXXIV	1974
    MMMM		4000		выше 1000 нет числа
    MMMMMMMMMXM	9990
    MMMMMMMMMM	10000

    MM	>  MCMXCIX
    2000	>  1999

    --------------------------
    I	unus
    II	duo
    III	tres
    IV	quattuor
    V	quinque
    VI	sex
    VII	septem
    VIII	octo
    IX	nonem
    X	decem
    XI	undecim
    XII	duodecim
    XIII	tredecim
    XIV	quattuordecim
    XV	quindecim
    XVI	sedecim
    XVII	septedecim
    XVIII	duodeviginiti
    XIX	undeviginiti
    XX	viginity
    XXI	vigibiti unus

    XXVIII	duodetriginta
    XXIX	undetriginta
    XXX	triginta
    XL	quadraginta
    L	quinquaginta
    LX	sexaginta
    LXX	septuaginta
    LXXX	octoginta
    XC	nonaginta
    C	centum
    CC	ducenti
    CCC	trecenti
    CD	quadringenti
    D	quingenti
    DC	sexcenti
    DCC	septingenti
    DCCC	octingenti
    CM	nongenti
    M	mille
    MM	duo millia
    --------------------------

  Древнеегипетская

Чистая непозиционная система.
Значение числа - сумме значений цифр его составляющих.

  Вавилонская

Ноль (Вавилонцы придумали первыми)

Прямой клин - 1

Лежащий клин - 10

Шекели и Мины.

Таблицу умножения никто не учил (все таки 60x60).

Наследие от вавилона:
    24 часа		60 минут	60 секунд
    360 градусов	60 минут	60 секунд

Разряды - позиционные, но разряд это не цифра, а непозиционная группа цифр.

  Греческая

Алфавитная.

  Ацтеки и Майя

В основном группы по 5 предметов.

  Китай

  Древнерусская

Основу составляли алфавитные знаки на 1000.

Затем добавлялись модификаторы

    -------------
    Тьма народу
    Тьма Тьмущая
    -------------

Вообще строго говоря - было две системы (и числа писались
одними и теми же цифрами):
 ------------------------------------------------------------
        Малое число	Великое славянское число
 ------------------------------------------------------------
Тьма		10^4		10^6
Легион		10^5		10^12
Леодр		10^6		10^24
Ворон				10^48
Колода				10^50
 ------------------------------------------------------------

Считалось что числа больше колоды не нужны:
"Боле сего несть человеческому уму разумевати"

  Различные народы

  Смешанные СЧ

(СЧ со смешанным основанием)

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

    1 день    = 24 часа
    1 час     = 60 минут
    1 минута  = 60 секунд
    1 секунда = 100 сотых секунды
Основание = [24, 60, 60, 100]

    круг	  = 360 градусов
    градус	  = 60 минут
    минута    = 60 секунд
    секунда   = 100 сотых секунды

Основание = [360, 60, 60, 100]


3.2. ПОЗИЦИОННЫЕ СИСТЕМЫ СЧИСЛЕНИЯ

Обозначения:
    X ^ Y = возвести X в степень Y

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

Пример:

    1234 [10] =  1 * 1000 + 2 * 100 + 3 * 20 + 4
          =  1 * 10^3 + 2 * 10^2 + 3 * 10^1 + 4 * 10^0

    p - основание системы счисления
        цифры от (0..p-1)

        Правило: от 0 до 9 - арабские цифры
             от 10 до 36 - буквы англиского алфавита
                   A - 10
                   B - 11
                   ...
                   Z - 36
             более 36 - нет стандартных обозначений

Цифры:

0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Общая формула:

    N = aK * p^K + ... + a2 * p^2 + a1 * p^1 + a0

N - число
Записывается как (aK...a2a1a0) {p}
(основание степени записывается десятичным числом)

Пример:

    123 {10}	21 {4}		2aef {16}

Так же происходит обобщение и на дробные числа

    N = aK * p^K + ... + a2 * p^2 + a1 * p^1 + a0 +
        a{-1} * p^(-1) + a{-2} * p^(-2) + .... + a{-M} * p^(-M)

Напоминаем:
    P^(-K) =  1 / P^K

Пример:

    123.25 {10}	21.133 {4}	2aef.bc {16}

Самое смешное что единичная система счисления (унитарная) тоже подпадает под
позиционные СЧ, но она настолько вырожденная что является непозиционной.

Основание СЧ p = 1.

Базис:   1,1,1,1...
Есть только одна цифра (назовем ее 1).

    N = ak * 1 + a(k-1)*1 + .... + a0*1

    1	-  1
    11	-  2
    111	-  3
    1111	-  4
итд


3.3. СХЕМА ГОРНЕРА И ПРЕОБРАЗОВАНИЯ В ДРУГУЮ СИСТЕМУ СЧИСТЛЕНИЯ

    N = aK * p^K + ... + a2 * p^2 + a1 * p^1 + a0

можно представить в виде

    N = a0 + p * (a1 + p * (a2 + ... + p(a[K-1] + p*aK))..))

Схема Горнера - ключ к переводу чисел в другие системы счистления.

Пример:
    N = a0 + p * (a1 + p * (a2 + p * a3))

        делим N/p
        /     \
  ^	остаток       частное
  |	  a0	       a1 + p * (a2 + p * a3))   > p
  |		       делим на p
  |		      /       \
   \		   остаток    частное
     \		    a1         a2 + p * a3    > p
       \			делим на p
     \			/      \
       \		    остаток    частное
         \		      a2         a3     < p
           \
              +----------------------------
              берем остатки в этом направлении

    Число N = (a3a2a1a0) {p}

Пример:
    Переведем  3287 {10} в {7}
    Делим в столбик:

    3287|7
    ----+---
    ^ 	   4|469|7
     \	     ---+--
       \       0|67|7
     \	 --+-
       \	  4|9|7
         \	    -+-
               \    2|1
                 +-----

    3287 {10} =  12404 {7}

Другой пример:
    Перевод 100 {10} в {2}

    100| 2
^       ---+--
|	  0|50|2
|	    --+--
|	     0|25|2
|	       --+--
|		1|12|2
|		  --+-
|		   0|6|2
|		     -+-
|		     0|3|2
|		       -+-
|		       1|1
+---------------------------

    100 {10} = 1100100 {2}


3.3.1. ДРОБНЫЕ ЧИСЛА

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

    (.a1!a2!a3!..)[n] = a1! * n^(-1) + a2! * n^(-2) .... итд

Для двоичной системы:
    -------------------
    .0	= 0
    .1	= 1/2

    .00	= 0
    .01	= 1/4
    .10	= 2/4 = 1/2
    .11	= 3/4

    .000	= 0
    .001	= 1/8
    .010	= 2/8 = 1/4
    .011	= 3/8
    .100	= 4/8 = 1/2
    .101	= 5/8
    .110	= 6/8 = 3/4
    .111	= 7/8
    -------------------

итд

Для преобразования их в другую систему счисления:

Обоснование:
        A = c0 * b^-1 + c1 * b^-2 + ....
          A*b = c0 (целое) + с1 * b^-1 + ...
         A*b - c0 = c1 * b^-1 + ...
   (A*b - c0) * b = c1 (целое) + ....

Пример 1:
    10.25 [10] = 10 1/4 [10] = 1010.01 [2]

Пример 2:
    3.75 десятичное в двоичную
    Целая часть	3 = 11
    Дробная
        0.75 * 2 = 1.50	 [1]
        0.50 * 2 = 1.00  [1]
        0.00	   закончили

    Итак 3.75 = 11.11

Пример 3:
    57.45 дестичное в двоичную систему:

    Целое переводится как обычно  57 = 111001
    Переводим дробную часть.
    Только на этот раз не делим, а умножаем и берем целую часть.

        0.45  *  2  = 0.90	[0]	2^-1    MSB
        0.90  *  2  = 1.80	[1]	2^-2     ^
        0.80  *  2  = 1.60	[1]	2^-3     |
        0.60  *  2  = 1.20	[1]	2^-4     |
        0.20  *  2  = 0.40      [0]     итд      |
        0.40  *  2  = 0.80	[0]              V
        0.80  *  2  = 1.60	[1]             LSB
            и все повторяется т.е. переодическая дробь
    57.45 = 111001.01(1100)

Пример 4:
    10.23 десятичное в троичную систему

    целую часть:
        10 | 3
    3^0   -> 1 +---
             3  | 3
       3^1   ->  0  +---
           3^2   -->  1

    целая часть = 101

    дробная часть.
        0.23 * 3  =  0.69	[0]	3^-1
        0.69 * 3  =  2.07	[2]	3^-2
        0.07 * 3  =  0.21	[0]	3^-3
        0.21 * 3  =  0.63	[0]	3^-4
        0.63 * 3  =  1.89	[1]	3^-5
        0.89 * 3  =  2.67	[2]	3^-6
        0.67 * 3  =  2.01	[2]	3^-7
        0.01 * 3  =  0.03	[0]	3^-8
        0.03 * 3  =  0.09	[0]	3^-9
        0.09 * 3  =  0.27	[0]	3^-10
        0.27 * 3  =  0.81	[0]	3^-11
        0.81 * 3  =  2.43	[2]	3^-12
        0.43 * 3  =  1.29	[1]	3^-13
        0.29 * 3  =  0.87	[0]	3^-14
        0.87 * 3  =  2.61	[2]	3^-15
        0.61 * 3  =  1.83	[1]	3^-16
        0.83 * 3  =  2.49	[2]	3^-17
        0.49 * 3  =  1.47	[1]	3^-18
        0.47 * 3  =  1.41	[1]	3^-19
        0.41 * 3  =  1.23	[1]	3^-20
        0.23 * 3  =  0.69	[0]	3^-21  повторение - дробь циклическая

    таким образом
        10.23 {10} = 101.(02001220000210212111) {3}


3.4.3. ЧЕТВЕРИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ

Цифры:   { 0, 1, 2, 3  }

Базис:
    ---------------
    P	4^P
    ---------------
    5	1024
    4	256
    3	64
    2	16
    1	4
    0	1
    -1	1/4
    -2	1/16
    -3	1/64
    ---------------

Числа:
     ---------------
     0	0
     1	1
     2	2
     3	3
    10	4
    11	5
    12	6
    13	7
    20	8
    21	9
    22	10
    23	11
    30	12
    31	13
    32	14
    33	15
       100	16
     ---------------

Дробные числа:
     ---------------
    .0	0
    .1	0.25	= 1/4
    .2	0.50    = 2/4 = 1/2
    .3	0.75	= 3/4

    .01	0.0625	= 1/16
    .02	0.125	= 2/16 = 1/8
    .03
    .10	0.25	= 4/16 = 2/8 = 1/4
    ...
    .20	0.5	= 8/16 = 4/8 = 2/4 = 1/2
    ...
    .11	0.9375	 = 15/16
     ---------------

Таблица сложения:

    +  |  0   1   2   3
    ---+----------------
    0  |  0   1   2   3
    1  |  1   2   3  10
    2  |  2   3  10  11
    3  |  3	 10  11  12

Таблица умножения:

    *  |  0   1   2   3
    ---+----------------
    0  |  0   0   0   0
    1  |  0   1   2   3
    2  |  0   2  10  12
    3  |  0	  3  12  21

Напрямую отображается в двоичную:

    +---+---+
    |   |   |	2 бита на одну цифру
    +---+---+

    ---------
    00	0
    01	1
    10	2
    11	3
    ---------


3.4.4. ВОСМЕРИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ

Цифры: { 0, 1, 2, 3, 4, 5, 6, 7 }

Базис:
    -----------------
    P	8^P
    -----------------
    4	4096
    3	512
    2	64
    1	8
    0	1
    -1	1/8
    -2	1/64
    -----------------

Дробные числа:
    -----------------
    .0	0
    .1	1/8	0.125
    .2	1/4     0.25
    .3	3/8     0.375
    .4	1/2     0.5
    .5	5/8     0.625
    .6	6/8     0.75
    .7	7/8     0.875
    ...
    .47	47/64	0.734375
    ------------------

Таблица сложния для восмеричной системы счистления:
----------------------------------------
 +  |  0   1   2   3   4   5   6   7
----------------------------------------
0   |  000 001 002 003 004 005 006 007
1   |  001 002 003 004 005 006 007 010
2   |  002 003 004 005 006 007 010 011
3   |  003 004 005 006 007 010 011 012
4   |  004 005 006 007 010 011 012 013
5   |  005 006 007 010 011 012 013 014
6   |  006 007 010 011 012 013 014 015
7   |  007 010 011 012 013 014 015 016
----------------------------------------

Таблица умножения для восмеричной системы счисления:
---------------------------------------
 *  |  0   1   2   3   4   5   6   7
---------------------------------------
0   |  000 000 000 000 000 000 000 000
1   |  000 001 002 003 004 005 006 007
2   |  000 002 004 006 010 012 014 016
3   |  000 003 006 011 014 017 022 025
4   |  000 004 010 014 020 024 030 034
5   |  000 005 012 017 024 031 036 043
6   |  000 006 014 022 030 036 044 052
7   |  000 007 016 025 034 043 052 061
---------------------------------------

Напрямую отображается в двоичную:

    +---+---+---+
    |   |   |   |	3 бита на одну цифру
    +---+---+---+

    ---------
    000	0
    001	1
    010	2
    011	3
    100	4
    101	5
    110	6
    111	7
    ---------


3.4.5. ДЕСЯТИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ

Цифры: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }

С детства учили именно ее.

Базис:
    --------------------
    P	10^P
    --------------------
    5	100000
    4	10000
    3	1000
    2	100
    1	10
    0	1
    -1	0.1
    -2	0.01
    -3	0.001
    -4	0.0001
    --------------------

Таблица сложения
-------------------------------------
 +  |  0  1  2  3  4  5  6  7  8  9
-------------------------------------
0   |  00 01 02 03 04 05 06 07 08 09
1   |  01 02 03 04 05 06 07 08 09 10
2   |  02 03 04 05 06 07 08 09 10 11
3   |  03 04 05 06 07 08 09 10 11 12
4   |  04 05 06 07 08 09 10 11 12 13
5   |  05 06 07 08 09 10 11 12 13 14
6   |  06 07 08 09 10 11 12 13 14 15
7   |  07 08 09 10 11 12 13 14 15 16
8   |  08 09 10 11 12 13 14 15 16 17
9   |  09 10 11 12 13 14 15 16 17 18
-------------------------------------

Таблица умножения
-------------------------------------
 *  |  0  1  2  3  4  5  6  7  8  9
-------------------------------------
0   |  00 00 00 00 00 00 00 00 00 00
1   |  00 01 02 03 04 05 06 07 08 09
2   |  00 02 04 06 08 10 12 14 16 18
3   |  00 03 06 09 12 15 18 21 24 27
4   |  00 04 08 12 16 20 24 28 32 36
5   |  00 05 10 15 20 25 30 35 40 45
6   |  00 06 12 18 24 30 36 42 48 54
7   |  00 07 14 21 28 35 42 49 56 63
8   |  00 08 16 24 32 40 48 56 64 72
9   |  00 09 18 27 36 45 54 63 72 81
-------------------------------------


3.3.6. ШЕСТНАДЦИТЕРИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ

Цифры: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F }

Базис:
    -------------------
    P	16^P
    -------------------
    5	1048576
    4	65536
    3	4096
    2	256
    1	16
    0	1
    -1	1/16
    -2	1/256
    -3	1/4096
    -------------------

Таблица сложения для шестнадцитеричной системы счисления:
------------------------------------------------------
 +  |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
------------------------------------------------------
0   |  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
1   |  01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10
2   |  02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11
3   |  03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12
4   |  04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13
5   |  05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14
6   |  06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15
7   |  07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16
8   |  08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17
9   |  09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18
A   |  0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19
B   |  0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A
C   |  0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B
D   |  0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C
E   |  0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D
F   |  0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E
------------------------------------------------------

Таблица умножения для шестнадцитеричной системы счисления:
------------------------------------------------------
 *  |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
------------------------------------------------------
0   |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1   |  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
2   |  00 02 04 06 08 0A 0C 0E 10 12 14 16 18 1A 1C 1E
3   |  00 03 06 09 0C 0F 12 15 18 1B 1E 21 24 27 2A 2D
4   |  00 04 08 0C 10 14 18 1C 20 24 28 2C 30 34 38 3C
5   |  00 05 0A 0F 14 19 1E 23 28 2D 32 37 3C 41 46 4B
6   |  00 06 0C 12 18 1E 24 2A 30 36 3C 42 48 4E 54 5A
7   |  00 07 0E 15 1C 23 2A 31 38 3F 46 4D 54 5B 62 69
8   |  00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78
9   |  00 09 12 1B 24 2D 36 3F 48 51 5A 63 6C 75 7E 87
A   |  00 0A 14 1E 28 32 3C 46 50 5A 64 6E 78 82 8C 96
B   |  00 0B 16 21 2C 37 42 4D 58 63 6E 79 84 8F 9A A5
C   |  00 0C 18 24 30 3C 48 54 60 6C 78 84 90 9C A8 B4
D   |  00 0D 1A 27 34 41 4E 5B 68 75 82 8F 9C A9 B6 C3
E   |  00 0E 1C 2A 38 46 54 62 70 7E 8C 9A A8 B6 C4 D2
F   |  00 0F 1E 2D 3C 4B 5A 69 78 87 96 A5 B4 C3 D2 E1
------------------------------------------------------

Напрямую отображается в двоичную:

    +---+---+---+---+
    |   |   |   |	|   4 бита на одну цифру
    +---+---+---+---+

    +-------+-------+
    |	|	|   2 знака в четвкричной системе
    +-------+-------+

    ---------
    0000	0
    0001	1
    0010	2
    0011	3
    0100	4
    0101	5
    0110	6
    0111	7
    1000	8
    1001	9
    1010	A
    1011	B
    1100	C
    1101	D
    1110	E
    1111	F
    ---------


3.4.7. СИСТЕМА СЧИСЛЕНИЯ С ОСНОВАНИЕМ 36

В Англиском языке 26 букв, естественным путем получается записать системы
счисления с основанием до 36 включительно.

Пример для системы счисления с основанием 36:
    0-9	цифры 0..9
    A-Z	цифры 10..35

Цифры: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H,
         I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z }

Базис:
    -------------------
    P	36^P
    -------------------
    4	1679616
    3	46656
    2	1296
    1	36
    0	1
    -1	1/36
    -2	1/1296
    -------------------

Таблица сложения для системы счисления с основанием 36:
-------------------------------------------------------------------------------------------------------------------
+   |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z
-------------------------------------------------------------------------------------------------------------------
0   |  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z
1   |  01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10
2   |  02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11
3   |  03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12
4   |  04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13
5   |  05 06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14
6   |  06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15
7   |  07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16
8   |  08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17
9   |  09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18
A   |  0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19
B   |  0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A
C   |  0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B
D   |  0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C
E   |  0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D
F   |  0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E
G   |  0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
H   |  0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G
I   |  0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H
J   |  0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I
K   |  0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J
L   |  0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K
M   |  0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L
N   |  0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M
O   |  0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N
P   |  0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O
Q   |  0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P
R   |  0R 0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q
S   |  0S 0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R
T   |  0T 0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S
U   |  0U 0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T
V   |  0V 0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T 1U
W   |  0W 0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T 1U 1V
X   |  0X 0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T 1U 1V 1W
Y   |  0Y 0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T 1U 1V 1W 1X
Z   |  0Z 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L 1M 1N 1O 1P 1Q 1R 1S 1T 1U 1V 1W 1X 1Y
-------------------------------------------------------------------------------------------------------------------

Таблица умножения для системы счисления с основанием 36:
-------------------------------------------------------------------------------------------------------------------
*   |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z
-------------------------------------------------------------------------------------------------------------------
0   |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1   |  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0G 0H 0I 0J 0K 0L 0M 0N 0O 0P 0Q 0R 0S 0T 0U 0V 0W 0X 0Y 0Z
2   |  00 02 04 06 08 0A 0C 0E 0G 0I 0K 0M 0O 0Q 0S 0U 0W 0Y 10 12 14 16 18 1A 1C 1E 1G 1I 1K 1M 1O 1Q 1S 1U 1W 1Y
3   |  00 03 06 09 0C 0F 0I 0L 0O 0R 0U 0X 10 13 16 19 1C 1F 1I 1L 1O 1R 1U 1X 20 23 26 29 2C 2F 2I 2L 2O 2R 2U 2X
4   |  00 04 08 0C 0G 0K 0O 0S 0W 10 14 18 1C 1G 1K 1O 1S 1W 20 24 28 2C 2G 2K 2O 2S 2W 30 34 38 3C 3G 3K 3O 3S 3W
5   |  00 05 0A 0F 0K 0P 0U 0Z 14 19 1E 1J 1O 1T 1Y 23 28 2D 2I 2N 2S 2X 32 37 3C 3H 3M 3R 3W 41 46 4B 4G 4L 4Q 4V
6   |  00 06 0C 0I 0O 0U 10 16 1C 1I 1O 1U 20 26 2C 2I 2O 2U 30 36 3C 3I 3O 3U 40 46 4C 4I 4O 4U 50 56 5C 5I 5O 5U
7   |  00 07 0E 0L 0S 0Z 16 1D 1K 1R 1Y 25 2C 2J 2Q 2X 34 3B 3I 3P 3W 43 4A 4H 4O 4V 52 59 5G 5N 5U 61 68 6F 6M 6T
8   |  00 08 0G 0O 0W 14 1C 1K 1S 20 28 2G 2O 2W 34 3C 3K 3S 40 48 4G 4O 4W 54 5C 5K 5S 60 68 6G 6O 6W 74 7C 7K 7S
9   |  00 09 0I 0R 10 19 1I 1R 20 29 2I 2R 30 39 3I 3R 40 49 4I 4R 50 59 5I 5R 60 69 6I 6R 70 79 7I 7R 80 89 8I 8R
A   |  00 0A 0K 0U 14 1E 1O 1Y 28 2I 2S 32 3C 3M 3W 46 4G 4Q 50 5A 5K 5U 64 6E 6O 6Y 78 7I 7S 82 8C 8M 8W 96 9G 9Q
B   |  00 0B 0M 0X 18 1J 1U 25 2G 2R 32 3D 3O 3Z 4A 4L 4W 57 5I 5T 64 6F 6Q 71 7C 7N 7Y 89 8K 8V 96 9H 9S A3 AE AP
C   |  00 0C 0O 10 1C 1O 20 2C 2O 30 3C 3O 40 4C 4O 50 5C 5O 60 6C 6O 70 7C 7O 80 8C 8O 90 9C 9O A0 AC AO B0 BC BO
D   |  00 0D 0Q 13 1G 1T 26 2J 2W 39 3M 3Z 4C 4P 52 5F 5S 65 6I 6V 78 7L 7Y 8B 8O 91 9E 9R A4 AH AU B7 BK BX CA CN
E   |  00 0E 0S 16 1K 1Y 2C 2Q 34 3I 3W 4A 4O 52 5G 5U 68 6M 70 7E 7S 86 8K 8Y 9C 9Q A4 AI AW BA BO C2 CG CU D8 DM
F   |  00 0F 0U 19 1O 23 2I 2X 3C 3R 46 4L 50 5F 5U 69 6O 73 7I 7X 8C 8R 96 9L A0 AF AU B9 BO C3 CI CX DC DR E6 EL
G   |  00 0G 0W 1C 1S 28 2O 34 3K 40 4G 4W 5C 5S 68 6O 74 7K 80 8G 8W 9C 9S A8 AO B4 BK C0 CG CW DC DS E8 EO F4 FK
H   |  00 0H 0Y 1F 1W 2D 2U 3B 3S 49 4Q 57 5O 65 6M 73 7K 81 8I 8Z 9G 9X AE AV BC BT CA CR D8 DP E6 EN F4 FL G2 GJ
I   |  00 0I 10 1I 20 2I 30 3I 40 4I 50 5I 60 6I 70 7I 80 8I 90 9I A0 AI B0 BI C0 CI D0 DI E0 EI F0 FI G0 GI H0 HI
J   |  00 0J 12 1L 24 2N 36 3P 48 4R 5A 5T 6C 6V 7E 7X 8G 8Z 9I A1 AK B3 BM C5 CO D7 DQ E9 ES FB FU GD GW HF HY IH
K   |  00 0K 14 1O 28 2S 3C 3W 4G 50 5K 64 6O 78 7S 8C 8W 9G A0 AK B4 BO C8 CS DC DW EG F0 FK G4 GO H8 HS IC IW JG
L   |  00 0L 16 1R 2C 2X 3I 43 4O 59 5U 6F 70 7L 86 8R 9C 9X AI B3 BO C9 CU DF E0 EL F6 FR GC GX HI I3 IO J9 JU KF
M   |  00 0M 18 1U 2G 32 3O 4A 4W 5I 64 6Q 7C 7Y 8K 96 9S AE B0 BM C8 CU DG E2 EO FA FW GI H4 HQ IC IY JK K6 KS LE
N   |  00 0N 1A 1X 2K 37 3U 4H 54 5R 6E 71 7O 8B 8Y 9L A8 AV BI C5 CS DF E2 EP FC FZ GM H9 HW IJ J6 JT KG L3 LQ MD
O   |  00 0O 1C 20 2O 3C 40 4O 5C 60 6O 7C 80 8O 9C A0 AO BC C0 CO DC E0 EO FC G0 GO HC I0 IO JC K0 KO LC M0 MO NC
P   |  00 0P 1E 23 2S 3H 46 4V 5K 69 6Y 7N 8C 91 9Q AF B4 BT CI D7 DW EL FA FZ GO HD I2 IR JG K5 KU LJ M8 MX NM OB
Q   |  00 0Q 1G 26 2W 3M 4C 52 5S 6I 78 7Y 8O 9E A4 AU BK CA D0 DQ EG F6 FW GM HC I2 IS JI K8 KY LO ME N4 NU OK PA
R   |  00 0R 1I 29 30 3R 4I 59 60 6R 7I 89 90 9R AI B9 C0 CR DI E9 F0 FR GI H9 I0 IR JI K9 L0 LR MI N9 O0 OR PI Q9
S   |  00 0S 1K 2C 34 3W 4O 5G 68 70 7S 8K 9C A4 AW BO CG D8 E0 ES FK GC H4 HW IO JG K8 L0 LS MK NC O4 OW PO QG R8
T   |  00 0T 1M 2F 38 41 4U 5N 6G 79 82 8V 9O AH BA C3 CW DP EI FB G4 GX HQ IJ JC K5 KY LR MK ND O6 OZ PS QL RE S7
U   |  00 0U 1O 2I 3C 46 50 5U 6O 7I 8C 96 A0 AU BO CI DC E6 F0 FU GO HI IC J6 K0 KU LO MI NC O6 P0 PU QO RI SC T6
V   |  00 0V 1Q 2L 3G 4B 56 61 6W 7R 8M 9H AC B7 C2 CX DS EN FI GD H8 I3 IY JT KO LJ ME N9 O4 OZ PU QP RK SF TA U5
W   |  00 0W 1S 2O 3K 4G 5C 68 74 80 8W 9S AO BK CG DC E8 F4 G0 GW HS IO JK KG LC M8 N4 O0 OW PS QO RK SG TC U8 V4
X   |  00 0X 1U 2R 3O 4L 5I 6F 7C 89 96 A3 B0 BX CU DR EO FL GI HF IC J9 K6 L3 M0 MX NU OR PO QL RI SF TC U9 V6 W3
Y   |  00 0Y 1W 2U 3S 4Q 5O 6M 7K 8I 9G AE BC CA D8 E6 F4 G2 H0 HY IW JU KS LQ MO NM OK PI QG RE SC TA U8 V6 W4 X2
Z   |  00 0Z 1Y 2X 3W 4V 5U 6T 7S 8R 9Q AP BO CN DM EL FK GJ HI IH JG KF LE MD NC OB PA Q9 R8 S7 T6 U5 V4 W3 X2 Y1
-------------------------------------------------------------------------------------------------------------------


3.5. CБАЛАНСИРОВАННЫЕ СИСТЕМЫ СЧИСЛЕНИЯ

Цифры:
    { N, 1, 0, 1#, ... N# }

    1# = -1
    2# = -2
    ...
    N# = -3

    для сбалансированной системы счисления с основанием 2N + 1

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

Базис такой же как и у обычной несбалансированной системы.


3.5.3. СБАЛАНСИРОВАННАЯ ДЕВЯТНАДЦАТИРИЧНАЯ СИСТЕМА СЧИСЛЕНИЯ

Эта система даже используется на практике ;)

           _  _  _  _  _  _  _  _  _
Цифры:  {  9, 8, 7, 6, 5, 4, 3, 2, 1,
       0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  }

Преймущества:  таблицы сложения/умножения как у десятичной системы
           (надо лишь учесть знак цифры)

        19^2 = 361 (можно 2мя цифрами записать угол (360')

Пример:
    хотим записать угол 45':
        45 = 38 + 7 = 19*2 + 7 =       27

    хотим записать угол 50':
        50 = 38 + 12
            12 >  (19-1)/2
        поэтому:                        _
        50 = 57 - 7 = 19*3 - 7  =      37


3.5.4. ИЗБЫТОЧНАЯ СБАЛАНСИРОВАННАЯ СИСТЕМА С ОСНОВАНИЕМ 4

Цифры:	{2, 1, 0, 1#, 2#}

Базис
    -------------------
    P	4^P
    -------------------
    4	256
    3	64
    2	16
    1	4
    0	1
    -1	1/4
    -2	1/16
    -3	1/64
    -------------------

Числа:

   -----------------------------------------
        2# 2	-6
    1# 2#   -6
    1# 1#   -5
    1# 0    -4
        1# 1    -3
    1# 2    -2
       2#   -2
       1#	-1
           0	0
       1	1
       2	2
    1  2#	2
    1  1#	3
    1  0	4
    1  1	5
    1  2	6
    2  2#   6
    2  1#   7
    2  0    8
    2  1	9
    2  2	10
     1  2# 2#   6
     1  2# 1#   7
     1  2# 0    8
     1  2# 1    9
     1  2# 2    10
     1  1# 2#   10
     1  1# 1#   11
     1  1# 0	12
     1  1# 1    13
     1  1# 2    14
     1  0  2#   14
     1  0  1#   15
     1  0  0    16
     1  0  1    17
     1  0  2	18
     1  1  2#   18
     1  1  1#   19
     1  1  0    20
     1  1  1    21
     1  1  2    22
     1  2  2#   22
   -----------------------------------------

Видно что система обладает избыточностью:

Например 6 это:

    1 2  = 2 2# = 1 2# 2#

Свертки:

    ... 0 2 ...  = ... 1 2# ...
          2	     =     4 - 2

    ... 1 2 ...  = ... 2 2# ...
        4 + 2    =     8 - 2

    ... 2 2 ...  = ... 1 1# 2# ...
        8 + 2    =     16 - 4 - 2

    ... 1# 2 ..  = ...  0 2# ...

    ... 2# 2 ..  = ...  1# 2# ...

Таблица сложения
(обратите внимание отличается от таблицы сложения в сбалансированной пятиричной)

    + |   2    1    0     1#     2#
       ---+-------------------------------
    2 | 10    11#   2     1      0
    1 | 11#    2    1     0      1#
    0 |  2     1    0     1#     2#
       1# |  1     0    1#    2#   1#1
       2# |  0     1#   2#  1#1    1#0

Таблица умножения
(отличается от таблицы умножения в сбалансированной пятиричной)

    * |   2    1    0     1#     2#
       ---+-------------------------------
        2 |  10    2    0     2#   1#0
        1 |   2    1    0     1#     2#
        0 |   0    0    0     0      0
       1# |   2#   1#   0     1      2
       2# | 1#0    2#   0     2     10

Преобразование из четверичной системы:

    -----------------
    Radix4	Radix4#
    -----------------
    0	00
    1	01
    2	02  или	12#
    3	11#
    -----------------


3.5.5. НЕИЗБЫТОЧНАЯ ЧАСТИЧНО-СБАЛАНСИРОВАННАЯ СИСТЕМА С ОСНОВАНИЕМ 4

Цифры:	{2, 1, 0, 1#}

Базис
    -------------------
    P	4^P
    -------------------
    4	256
    3	64
    2	16
    1	4
    0	1
    -1	1/4
    -2	1/16
    -3	1/64
    -------------------

Числа:

   -----------------------------------------
  1# 0  1#	-17
  1# 0  0	-16
  1# 0  1	-15
  1# 0  2	-14
  1# 1  1#	-13
  1# 1  0	-12
  1# 1  1	-11
  1# 1  2	-10
  1# 2  1#	-9
  1# 2  0	-8
  1# 2  1	-7
  1# 2  2	-6
     1# 1#	-5
     1# 0	-4
     1# 1	-3
     1# 2	-2
    1#	-1
    0	0
    1	1
    2	2
     1  1#	3
     1  0	4
     1  1	5
     1  2	6
     2  1#	7
     2  0	8
     2  1	9
     2  2	10
  1  1# 1#	11
  1  1# 0	12
  1  1# 1	13
  1  1# 2	14
  1  0  1#	15
  1  0  0	16
  1  0  1	17
   -----------------------------------------

Таблица сложения:

    + |   2    1    0     1#
       ---+------------------------
    2 | 10    11#   2     1
    1 | 11#    2    1     0
    0 |  2     1    0     1#
       1# |  1     0    1#  1#2

Таблица умножения:

    * |   2    1    0     1#
       ---+-----------------------
        2 |  10    2    0   1#2
        1 |   2    1    0     1#
        0 |   0    0    0     0
       1# | 1#2    1#   0     1

Преобразование из четверичной системы:

    -----------------
    Radix4	Radix4#
    -----------------
    0	00
    1	01
    2	02
    3	11#
    -----------------


3.5.6. СБАЛАНСИРОВАННАЯ ДЕВЯТИРИЧНАЯ СИСТЕМА СЧИСЛЕНИЯ

Сбалансированная девятирияная система для сбалансированной троичной играет
туже роль, что и шестнадцатиричная система для двоичной.

Цифры
    { d, c, b, a, 0, 1, 2, 3, 4 }

    a = -1
    b = -2
    c = -3
    d = -4

Каждый разряд сбалансированной девятиричной системы содержит два разряда
сбалансированной троичной.

 ------------------------------------------------------------
Цифра   	d    c    b    a    0    1    2    3    4
Триты		--   -0   -+   0-   00   0+   +-   +0   ++
Значение	-4   -3   -2   -1   0    1    2    3    4
 ------------------------------------------------------------

Сответсвенно три цифры описывают трайт.
Значения трайта лежат от ddd (-364{dec}) до 444 (364{dec}).

Базис:
    -------------------
    P	9^P
    -------------------
    4	6561
    3	729
    2	81
    1	9
    0	1
    -1	1/9
    -2	1/81
    -3	1/729
    -------------------

Числа:
    ---------------------
    b0	-18
    b1	-17
    b2	-16
    b3	-15
    b4	-14
    ad	-13
    ac	-12
    ab	-11
    aa	-10
    a0	-9
    a1	-8
    a2	-7
    a3	-6
    a4	-5
    d	-4
    c	-3
    b	-2
    a	-1
    0	0
    1	1
    2	2
    3	3
    4	4
    1d	5
    1c	6
    1b	7
    1a	8
    10	9
    11	10
    12	11
    13	12
    14	13
    2d	14
    2c	15
    2b	16
    2a	17
    20	18
    21	19
    22	20
    ---------------------

Таблица сложения

     + |  4   3   2   1   0   a   b   c   d
   ----+----------------------------------------
     4 | 1a   1b  1c  1d  4   3   2   1   0
     3 | 1b   1c  1d  4   3   2   1   0   a
     2 | 1c   1d  4   3   2   1   0   a   b
     1 | 1d   4   3   2   1   0   a   b   c
     0 |  4   3   2   1   0   a   b   c   d
     a |  3   2   1   0   a   b   c   d   a4
     b |  2   1   0   a   b   c   d   a4  a3
     c |  1   0   a   b   c   d   a4  a3  a2
     d |  0   a   b   c   d   a4  a3  a2  a1

Таблица умножения

     * |  4   3   2   1   0   a   b   c   d
   ----+----------------------------------------
     4 |  2b  13  1a  4   0   d   a1  ac  b2
     3 |  13  10  1c  3   0   c   a3  a0  ac
     2 |  1a  1c  4   2   0   b   d   a3  a1
     1 |  4   3   2   1   0   a   b   c   d
     0 |  0   0   0   0   0   0   0   0   0
     a |  d   c   b   a   0   1   2   3   4
     b |  a1  a3  d   b   0   2   4   1c  1a
     c |  ac  a0  a3  c   0   3   1c  10  13
     d |  b2  ac  a1  d   0   4   1a  13  2b


3.6. CИСТЕМА СЧИСЛЕНИЯ С ОСНОВАНИЕМ -2

(можем ее назвать нега-двоичная)

Позволяет выразить число не указывая его знак

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

Цифры:  1 и 0
    { 0, 1 }

    (aN...a1a0){-2} = aN * (-2)^N + ... + a2 * (-2)^2 + a1 * (-2) + a0

Базис:
    --------------------------
    P	(-2)^P
    --------------------------
    6	64
    5 	-32
    4	16
    3	-8
    2	4
    1	-2
    0	1
    -1	-1/2
    -2	1/4
    -3	-1/8
    -4	1/16
    -5	-1/32
    -6	1/64
    --------------------------

Числа:
    ----------------------------
    0000	0 	0
    0001	1       1
    0010	-2      -2
    0011	-1      -2+1
    0100	4       4
    0101	5       4+1
    0110	2       4-2
    0111	3       4-2+1
    1000	-8      -8
    1001	-7      -8+1
    1010	-10     -8-2
    1011	-9      -8-2+1
    1100	-4      -8+4
    1101	-3      -8+4+1
    1110	-6      -8+4-2
    1111	-5      -8+4-2+1
    ----------------------------

Дробные числа:
    ----------------------------
    .1	-1/2	-0.5

    .00	0        0
    .01	1/4      0.25
    .10	-1/2    -0.5
    .11	-1/4    -0.25

    .001	-1/8    -0.125
    .010	1/4      0.25
    .011	1/8      0.125
    .100	-1/2    -0.5
    .101	-5/8    -0.625
    .110	-1/4    -0.25
    .111	-3/8    -0.375

    .0001	1/16     0.0625
    .0010	-1/8    -0.125
    .0011	-1/16   -0.0625
    .0100	1/4      0.25
    .0101	5/16     0.3125
    .0110	1/8      0.125
    .0111	3/16     0.1875
    .1000	-1/2    -0.5
    .1001	-7/16   -0.4375
    .1010	-5/8    -0.625
    .1011	-9/16   -0.5625
    .1100	-1/4    -0.25
    .1101	-3/16   -0.1875
    .1110	-3/8    -0.375
    .1111	-5/16   -0.3125
    ----------------------------

    ---------------------------
    1/8	.011
    2/8	.01
    3/8    1.1010	   1 - 5/8
    4/8    1.1	   1 - 1/2
    5/8    1.111	   1 - 3/8
    6/8    1.11	   1 - 1/4
        7/8    1.001	   1 - 1/8
    ---------------------------
       -1/8     .001
       -2/8	.11
       -3/8	.111
       -4/8	.1
       -5/8     .101
       -6/8   11.01	    -2 + 1 + 1/4
       -7/8   11.011	    -2 + 1 + 1/8
    ---------------------------

Интересно соотношение положительных/отрицательных чисел которые можно представить
N разрядами:

        вообще
          +-----------+
          |	          |
    ---------------------------------------
    N	+	-	+Last	-Last
    ---------------------------------------
    1	2	-	2	0
    2	2	2	0	2
    3	6	2       4	0
    4	6	10	0	8
    ---------------------------------------
                  |             |
                  +-------------+
                последним разрядом

Таблица сложения:

         + |   0    1
    ---+-----------
     0 |   0    1
     1 |   1  110

Таблица умножения:

    *  |   0   1
    ---+----------
         0 |   0   0
         1 |   0   1

Правила сложения:

    1 + 1		= 110	при сложении могут быть 2 бита переноса
    1 + 11  	= 0
    1 + 1 + 1       = 111

    0  - 1		= 11
    11 - 1		= 10


3.7. СИСТЕМЫ СЧИСЛЕНИЯ С КОМПЛЕКСНЫМИ ОСНОВАНИЯМИ

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

  2i

МНИМОЧЕТВЕРИЧНАЯ СИСТЕМА СЧИСЛЕНИЯ

Основание системы счисления:  2i
Цифры {0,1,2,3}

Базис для системы с основанием 2i на комплексной плоскости:

    ---------------------
    P	(2I)^P
    ---------------------
    8		256
    7		-128I
    6		-64
    5		32I
    4		16
    3		-8I
    2		-4
    1		2I
    0		1
    -1		-I/2
    -2		-1/4
    -3		I/8
    -4		1/16
    -5		-I/32
    -6		-1/64
    -7		I/128
    -8		1/256
    ---------------------

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

       0		= 0
       1		= 1
       2		= 2
       3		= 3
      10		= 2i
      11		= 2i + 1
      12		= 2i + 2
      13		= 2i + 3
      20		= 4i
      21		= 4i + 1
      22		= 4i + 2
      23		= 4i + 3
      30		= 6i
      31		= 6i + 1
      32 		= 6i + 2
      33		= 6i + 3
     100		= -4
     101		= -3
     102		= -2
     103		= -1
     110		= -4 + 2i
     111		= -3 + 2i
     112		= -2 + 2i
     113		= -1 + 2i
     120		= -4 + 4i
     121		= -3 + 4i
     122		= -2 + 4i
     123		= -1 + 4i
     130		= -4 + 6i
     131		= -3 + 6i
     132		= -2 + 6i
     133		= -1 + 6i

     210		= -8 + 2i
     211		= -7 + 2i
     212		= -6 + 2i
     213		= -5 + 2i

    1000		= -8i
       10000		= 16

    Некоторые нечетные мнимые числа выражаются дробями:

    10.2		= i

    1 * (2i) + 0*1 + 2 * (1 / 2i) = 2i + 2 / 2i   = 2i - i = i
                                        |      |
                        +------+
                        |
                        V
 ---------------------------------------------------------------------------------
    a1  b1   a2  b2     a1 a2  b1  b2   a2^2   b2^2
 2/2i = (2, 0) / (0, 2) = ( (2*0 + 0 * 2) / (0  +  4 )  , (0*0 - 2*2) / (0 + 4)) =

            = ( 0, -1) = -i
 ---------------------------------------------------------------------------------

(a{2n}...a[1] a[0] a[-1]...A[-2k]) {2i} =
    (a[2n]...a[2]a[0]a[-2]...a[-2k]) {-4}  +
    2i *(a[2n-1]...a[3] a[1] a[-1].... a[-2k+1]) {-4}

Дробные числа:
    -------------------------------
    .00     	0
    .01	        -1/4
    .02		-1/2
    .03		-3/4
    .10		-I/2
    .11		-1/4 - I/2
    .12		-1/2 - I/2
    .13		-3/4 - I/2
    .20		-I
    .21		-1/4 - I
    .22		-1/2 - I
    .23		-3/4 - I
    .30		-3I/2
    .31		-1/4 - 3I/2
    .32		-1/2 - 3I/2
    .33		-3/4 - 3I/2

    .00103		I/32	 = I/8 + 3*(-I/32)
        .00102		I/16     = I/8 + 2*(-I/32)
    .001		I/8
    .002		I/4
      10.3		I/2	 = 2I + 3*(-I/2)
      10.2		I	 = 2I +	2*(-I/2)
    .1		-I/2
    .102		-I/4	 = -I/2 + 2*(I/8)
    .103		-I/8	 = -I/2 + 3*(I/8)

    .0001		1/16
    .0002		1/8
       1.03		1/4	 = 1 - 3/4
       1.02		1/2	 = 1 - 1/2
       1.		1
    .02		-1/2
    .01		-1/4
    .0102		-1/8	 = -1/4 + 2*(1/16)
    .0103		-1/16	 = -1/4 + 3*(1/16)
    -------------------------------

  -i+1

СИСТЕМА СЧИСЛЕНИЯ С ОСНОВАНИЕМ -i+1

Система счистления с основанием (-i+1), где i - квадратный корень (-1)
позволяет выразить любое целое комплексное число

Цифры: 1 и 0
    { 0, 1 }

    a + b*i = (qr + qi * i) (-1 + i) + r
                r = 0 or 1

    qr = (b - a + r)/2
    qi = (-a -b + r)/2

    Если a и b оба четные/нечетные то  r = 0
    Если четность a и b разные то      r = 1

    (aN...a1a0){-1+i} = aN * (-1_i)^N + ... + a2 * (-1+i)^2 +
                + a1 * (-1+i) + a0

Базис для системы с основанием -i+1 на комплексной плоскости:

    ---------------------
    P	(-I+1)^P
    ---------------------
    8	16
    7	8 + 8I
    6	8I
    5	-4 + 4I
    4	-4
    3	-2 - 2I
    2	-2I
    1	1 - I
    0	1
    -1	(1 + I)/2
    -2	I/2
    -3	(-1 + I)/4
    -4	-1/4
    -5	(-1 - I)/8
    -6	-I/8
    -7	(1 - I)/16
    -8	1/16
    ---------------------

Числа:
    0000	0
    0001	1
    0010	-1+i
    0011	i
    0100	-2i
    0101	1-2i
    0111	-i
    1000	2+2i
    1001	3+2i
    1010	1+3i
    1011	2+3i
    1100	2
    1101	3
    1110	1+i
    1111	2+i

Правила сложения:

    1 + 1				= 1100
    1 + 1 + 1			= 1101
    1 + 1 + 1 + 1		        = 111010000
    1 + 1 + 1 + 1 + 1		= 111010001
    1 + 1 + 1 + 1 + 1 + 1		= 111011100
    1 + 1 + 1 + 1 + 1 + 1 + 1	= 111011101
    1 + 1 + 1 + 1 + 1 + 1 + 1 + 1	= 111000000

  -1+i

    -1+i = -(-i+1)

Сопряженные системы.
Битовая строка представляющая число a+bi в одной из этих систем представляет
a-bi.

    Пример
        {-i+1}  {-1+i}
        10

  -2i

СИСТЕМА СЧИСЛЕНИЯ С ОСНОВАНИЕМ -2i

    Однозначно отображается в систему с основанием -1+i, которая является
сопряжнной системе с основанием -i+1 которую мы рассмотрели.

    ---------------------
    {-2i}	{-1+i}	{10}
    ---------------------
    0	00	0
    1       01      1
    2       10      -1+i
    3       11      i
    ---------------------


3.8. НЕТРАДИЦИОННЫЕ СЧ (ЭКЗОТИКА)

  Фибоначиева система счисления

Пример довольно экзотической системы счистления - система основанная
на числах Фибоначи.
(Кстати она не позиционная, а со смешанным основанием).
(Пример смешанного основания: 7 дней 24 часа 60 минут 60 секунд).

Фибоначи

Числа Фибоначи определяются так:

    F0 = 0
    F1 = 1
    Fn = Fn-1 + Fn-2 (для n > 1)

 ---------------------------------------------------------------
   n 	0  1  2  3  4  5  6  7   8   9   10  11  12   13   14
  Fn    0  1  1  2  3  5  8  13  21  34  55  89  144  233  377
 ---------------------------------------------------------------
Собственно это и есть базис.

Правила для записи чисел:
    две единицы не могут стоять рядом в соседних разрядов
    (это правило для канонической формы)
    (запись начинаем Fn...F1)

    0	000000
    1	000001
    2	000010
    3	000100
    4	000101
    5	001000
    6	001001
    7	001010
    8	010000
    9	010001
    10	010010
    11	010100
    12	010101
    13	100000
    14	100001
    15	100010
    16	100100
    17	100101
    18	101000
    19	101001
    20	101010

Числа Фибоначи можно обобщить и в отрицательную сторону:
 ---------------------------------------------------------------
   n    0  -1  -2  -3  -4  -5  -6  -7  -8   -9  -10
  Fn    0   1  -1   2  -3   5  -8  13  -21  34  -55
 ---------------------------------------------------------------

не буду приводить систему счистления для отрицательных чисел Фибоначи

Примеры:
    37[10] = 34 + 3 = 10000000[Ф] + 100[Ф]            = 10000100[Ф]
     25[10] = 21 + 3 + 1 = 1000000 [Ф] + 100[Ф] + 1[Ф] =  1000101[Ф]

Система имеет избыточность.
т.е. одно и то же число можно представить различными способами:

    19 = 13 + 5 + 1
    19 = 13 + 3 + 2 + 1

Операции для переведения чисел в разные варианты:
    Свертка		011  ->   100
    Развертка	100  ->	  011

Минимальная форма числа:
    Если мы выполним все возможные свертки то получим минимальную форму

Максимальная форма числа:
    Если мы выполним все возможные развертки то получим максимальную форму

Пример:
    19 = 101001	13 + 5 + 1
           ***
         100111	13 + 3 + 2 + 1
         ***
         011111	8 + 5 + 3 + 2 + 1

Прибавление единицы (счетчики):
    сводится к свертке
    -------------------------------------------------------------
    0	0000000
    1	0000000 +  1 = 0000001 = 0000010
                    ##
    2	0000010 +  1 = 0000011 = 0000100
                   ***
    3	0000100 +  1 = 0000101 = 0000110 = 0001000
                    ##      ***
    4	0001000 +  1 = 0001001 = 0001010
                    ##
    5	0001010 +  1 = 0001011 = 0001100 = 0010000
                   ***     ***
    6	0010000 +  1 = 0010001 = 0010010
                    ##
    7	0010010 +  1 = 0010011 = 0010100
                   ***
    8	0010100 +  1 = 0010101 = 0010110 = 0011000 = 0100000
                                ##      ***     ***
    -------------------------------------------------------------

Соответсвенно вычитание 1 сводится к развертке

Для сравнения двух чисел в фибоначиевой системе надо их сначала привести к
минимальной форме.

Таблица сложения:
    F[k] + F[k] = F[k] + F[k-1] + F[k-2]
    F[k] + F[k] = F[k+1] + F[k+2]

    0 + 0  =  0
    0 + 1  =  1
    1 + 0  =  1
    1 + 1  =  1.11	    Появляются варианты
    1 + 1  = 10.01

Для операций сложения числа надо приводить к минимальной форме

Таблица вычитания:
    F[n+k] - F[n] = F[n+k-2] + F[n+k-3] + ... + F[n-1]

    0  - 0   =  0
    1  - 1   =  0
    1  - 0   =  0.11
    10 - 1   =  0.1
    100 - 1	 =  1.1
    1000 - 1 = 11.1

  Факториальная система счисления

    n! = 1 * 2 * ... * (n-1) * n
    0! = 1! = 1

    n!  (n-1)! ... 3!  2!  1!

A = An*n! + An-1*(n-1)! + .... + A2*2! + A1* 1! + ... A-1/2! + A-2/3! + ...

    0 <= Ai+1 <= i,	  i=1,2,...
    A0 не используется

Базис:
    ---------------------
    P	P!
    ---------------------
    10	3628800
    9	362880
    8	40320
    7	5040
    6	720
    5	120
    4	24
    3	6
    2	2
    1	1
    ---------------------

Примеры
     3221[ф!] = 3*4! + 2*3! + 2*2! + 1*1! = 89[10]
    40301[ф!] = 4*5! + 3*3! + 1*1!        = 499[10]


3.9. BCD

P-Q- системы счистления.

Имеют два основания.
В одном данные храняться, а в другом представляются.

  BCD

BCD is (Binary Coded Decimal).
Храняться десятичные данные в двоичном коде
Не все состояния двоичного кода являются допустимыми.

Классический BCD:
(Код 8-4-2-1)

    -----------------
    Число	Значение
    -----------------
    0	0000
    1	0001
    2	0010
    3	0011
    4	0100
    5	0101
    6	0110
    7	0111
    8	1000
    9	1001
    -----------------

Как вычислять?
Сложение/вычитание - после них коррекция

    +-+-+-+-+-+-+-+-+
    |       |       |
        +-+-+-+-+-+-+-+-+
    +
    +-+-+-+-+-+-+-+-+
    |       |       |
        +-+-+-+-+-+-+-+-+
    =  -------------------
    +-+-+-+-+-+-+-+-+
    |       |       |
        +-+-+-+-+-+-+-+-+
        ^ ------+--- возможно нужна коррекция
        |
        +------ возможен перенос.

        hex
        12
          + 75
              ----
        87	все хорошо

        hex
        019
          + 185
          -----
                19E	переноса нет но нужна коррекция младшего разряда  (+6)
          -----
        190
                 14	после коррекции возник перенос	(+1 в 2 разряде)
          -----
        1A4	нужна коррекция следущего разряда (+6 во 2м разряде)
          -----
        104
        10	после коррекции возник перенос (+1 в третьем разряде)
          -----
        204

        19
          + 28
          -----
        41 	число нормальное, но возник перенос, делаем коррекцию
          -----
        47

x86: команды DAA, DAS
DAA
    if ((AL and 0Fh) > 9 or (AF == 1))
    {
        AL <- AL + 6
        AF <- 1
    }
    if ((AL > 9Fh) or (CF == 1))
    {
        AL <- AL + 60h
        CF <-1
    }

DAS
    if ((AL and 0Fh) > 9 or (AF == 1))
    {
        AL <- AL - 6
        AF <- 1
    }
    if ((AL > 9Fh) or (CF == 1))
    {
        AL <- AL - 60h
        CF <- 1
    }

  BCD с избытком 3

BCD (код с избытком 3):
Преймущества BCD с избытком 3.

    -X = NOT(A) + 1

    2  	= 0101
    NOT(2)  = 1010 = 7
    7 + 1   = 1011 = 8
    -2	= 8		(10 - 2) = 8

    -----------------
    Число	Значение
    -----------------
        0	0011
    1	0100
    2	0101
    3	0110
    4	0111
    5	1000
    6	1001
    7	1010
    8	1011
    9	1100
    -----------------

Остальные комбинации не используются.

Еще одно преймущество - это относительная простота схем для сложения:

    C{p+1} =  0, если A{p} + B{p} + C{p} < 16
          1, если A{p} + B{p} + C{p} >= 16

    S{p}   =  A{p} + B{p} + C{p} + 13, если C{p+1} = 0
          A{p} + B{p} + C{p} + 3,  если C{p+1} = 0

  код 4221

Существуют и другие методы кодирования десятичных чисел в двоичные:
Например код 4221:

    --------------------
    Число	4221	4221
    --------------------
    0	0000
    1	0001
    2	0010
    3	0011
    4	1000
    5	0111	1001
    6	1100	1010
    7	1101	1011
    8	1110
    9	1111
    --------------------

  код 5421

Код 5421
Правило: если число >=5, то устанавливается бит 5.
Далее все однозначно.

    -------------
    Число	5421
    -------------
    0	0000
    1	0001
    2	0010
    3	0011
    4	0100
    5	1000
    6	1001
    7	1010
    8	1011
    9	1100
    -------------

  Унитарный код

Унитарный код (его еще называют кодом "1 из N")
Каждой цифре предоставляем свой разряд
(1 только в одной позиции N-разрядного кода)

    -------------------
    Число	Значение
    -------------------
    0	0000000001
    1	0000000010
    2	0000000100
    3	0000001000
    4	0000010000
    5	0000100000
    6	0001000000
    7	0010000000
    8	0100000000
    9	1000000000
    -------------------

  код 74210

Код 74210 (его еще называют "2 из 5") использует все возможные перестановки
из 5 символов с 2 единицами (их 10 штук).
Премущества - если один из битов измениться - сразу видно что ошибка.
Потому что число единиц будет нечетное.

    -----------------              --------------------
    Число	74210              	Перестановка Число
    -----------------              --------------------
    0	11000			XXX--   	1
    1	00011	                XX-X-           2
    2	00101	                X-XX-           4
    3	00110	                -XXX-           7
    4	01001	                XX--X           3
    5	01010	                X-X-X           5
    6	01100	                -XX-X           8
    7	10001	                X--XX           6
    8	10010	                -X-XX           9
    9	10100	                --XXX		0
    ----------------                --------------------


3.10.1. ПРОСТЫЕ ИРРАЦИОНАЛЬНЫЕ СЧ

Если мы берем иррациональное основание - что мы хотим?

    представление целых чисел
    дополнительные домены

  SQRT(2)

Основание: корень из двух = 1.414...

Цифры:	{ 0, 1 }

Базис:  { ..., 4, 2SQRT(2), 2, SQRT(2), 1, 1/SQRT(2), 1/2, ... }

Числа:
    --------------------
       0	0
       1	1
      10	sqrt(2)
      11	1 + sqrt(2)
     100	2
     101	3
     110	2 + sqrt(2)
     111	3 + sqrt(2)
    1000	2sqrt(2)
    1001	1 + 2sqrt(2)
    1010	3sqrt(2)
       0.1	1/sqrt(2)
       0.01 1/2
       0.11 1/2 + 1/sqrt(2)  обратите внимание это число больше единицы
    --------------------

Правила сложения:
     1 + 0  = 1
     1 + 1 	= 100

Таблица сложения:
    ------------
     + | 0   1
    ---+--------
     0 | 0   1
     1 | 1  100
    ------------

Таблица умножения:
    ------------
     * | 0  1
    ---+--------
     0 | 0  0
     1 | 0  1
    ------------

  SQRT(3)

По аналогии система с основанием корень из трех = 1.732...
Цифры:	{ 0, 1, 2 }

Базис:	{ ... 9, 3sqrt(3), 3, sqrt(3), 1, 1/sqrt(3), 1/3, ... }

Числа:
    -----------------------------
         0	  0
         1    1
         2    2
        10	  sqrt(3)
        11	  1 + sqrt(3)
        12    2 + sqrt(3)
        20    2sqrt(3)
       100    3
       101	  4
       102	  5
       200	  6
       201    7
       202	  8
      1000	  3sqrt(3)
     10000    9
         0.1  1/sqrt(3)
         0.2  2/sqrt(3)  тоже число большее единицы
    -----------------------------

Таблица сложения:
    ------------------
     +  |  0   1   2
    ------------------
     0  |  0   1   2
     1  |  1   2  100
     2  |  2  100 101
    ------------------

Таблица умножения:
    ------------------
     *  |  0   1   2
        ------------------
     0  |  0   0   0
     1  |  0   1   2
         2  |  0   2  101
    ------------------

    2 * 2 = 101		2*2 = 4
    20*20 = 10100		2*sqrt(3) * 2*sqrt(3) = 4 * 3 = 12 = 9 + 3

  SQRT(5)

Основание: sqrt(5) = 2.236...
Цифры:	{ 0, 1, 2, 3, 4 }

Базис:	{  ... 25,  5sqrt(5),  5,  sqrt(5), 1, 1/sqrt(5), 1/5 ... }

Числа:
    ---------------------------
          0     0
          1     1
          2     2
          3     3
          4     4
         10	    sqrt(5)
        100	    5
        101	    6
        102	    7
        103	    8
        104	    9
        110	    5 + sqrt(5)
        200	    10
        300	    15
        400	    20
        404     24
      10000	    25
          0.1   1/sqrt(5)
          0.4   4/sqrt(5)  понятное дело больше единицы
    ----------------------------

Таблица сложения:
    -----------------------
    + |  0   1   2   3   4
    --+--------------------
    0 |  0   1   2   3   4
    1 |  1   2   3   4  100
    2 |  2   3   4  100 101
    3 |  3   4  100 101 102
    4 |  4  100 101 102 103
    -----------------------

Таблица умножения:
    -----------------------------------
        *  |    0     1     2     3     4
    ---+-------------------------------
    0  |    0     0     0     0     0
    1  |    0     1     2     3     4
    2  |    0     2     4   101   103
    3  |    0     3   101   104   202
    4  |    0     4   103   202   301
    -----------------------------------

  2^(1/3)

Основание - кубический корень из двух = 1.2599...

Цифры:	{ 0, 1 }

Базис:	{ ... 2,  2^(2/3), 2^(1/3), 1, 1/2^(1/3), 1/2^(2/3), ... }

Числа:
    ----------------------------------
        0	0
        1	1
           10	2^(1/3)
           11	1 + 2^(1/3)
          100	2^(2/3)
          101	1 + 2^(2/3)
          110	2^(1/3) * (1 + 2^(1/3))
         1000	2
        10000	2*2^(1/3)
       100000	2*2^(2/3)
      1000000	4
        0.1	1/2^(1/3)
        0.01	1/2^(2/3)
        0.001	1/2
    ------------------------------------

Таблица сложения:
    ----------------
    +  |   0    1
    ---+------------
    0  |   0    1
    1  |   1  1000
    ----------------

Таблица умножения:
    ------------
     * | 0  1
    ---+--------
     0 | 0  0
     1 | 0  1
    ------------

  2^(2/3)

Основания системы счисления - 2^(2/3) = 1.587..

Цифры:   { 0, 1, 2, 3 }

Базис:	 { ...,  4, 2^(4/3),  2^(2/3), 1,  2^(-2/3), 2^(-4/3), 1/4, ... }

Числа:
    --------------------------------
        0	0
        1	1
        2	2
        3	3
           10	2^(2/3)
           11	1 + 2^(2/3)
          100	2^(4/3)
          101	1 + 2^(4/3)
          110	2^(2/3) + 2^(4/3)
         1000	4
    ---------------------------------

Таблица сложения:

    ---------------------------
    +   |   0     1     2     3
    ----+----------------------
    0   |	0     1     2     3
    1   |   1     2     3  1000
    2   |   2     3  1000  1001
    3   |   3  1000  1001  1002
    ---------------------------

Таблица умножения:

    ---------------------------
    *   |   0     1     2     3
    ----+----------------------
    0   |	0     0     0     0
    1   |   0     1     2     3
    2   |   0     2  1000  1002
    3   |   0     3  1002  2001
    ---------------------------


3.10.2 СИСТЕМА БЕРГМАНА

  Система Бергмана

Бергман

Цифры	{ 0, 1 }

Основание системы  t = [1 + SQRT(5)] / 2
Оно корень уравнения X^2 = X + 1
Обладает свойством:  t^N = t^(N-1) + t^(N-2)
Основана на золотом сечении

Позволяет представить все целые дробные и иррациональные числа
(Используются как положительные так и с отрицательные степени.

Базис для СЧ:
    {  ..., t^2, t,  1,  1/t, t^(-2), .... }

    ---------------------------
    t^(-3) =  1 / (2 + sqrt(5))
    t^(-2) =  2 / (3 + sqrt(5))
    t^(-1) =  2 / (1 + sqrt(5))
    t^0 =  1
    t^1 =  (1 + sqrt(5))/2
    t^2 =  (3 + sqrt(5))/2
    t^3 =  2 + sqrt(5)
    t^4 =  (7 + 3*sqrt(5))/2
    t^5 =  (1 + sqrt(5))^5/32
    t^6 =  9 + 4 * sqrt(5)
    ---------------------------

Числа:
    1	1.0
    2	10.01
    3	100.01
    4	101.01
    5	1000.1001   	t^3 + t^(-1) + t(-4)
    6	1010.0001
    7	10000.0001

  Троичная зеркально-симметричная СЧ

Получается скрещиванием системы Бергмана с сбалансированной троичной системой.
                _
Цифры	{ 1, 0, 1 }

    Используем как основание t^2 = (3 + sqrt(5))/2

Базис для СЧ:
    {  ..., t^4, t^2, 1, t^(-2), t^(-4), ... }

    t^(2N) + t^(2N) = t^(2*(N+1)) - t^(2N) + t^(2*(N-1))

Откуда таблица сложения:

    ----------------------------------
    +   |	   1#	    0	      1
    ----+-----------------------------
    1#  | 1# 1.1#	   1#	      0
    0   |      1#      0          1
    1   |	   0       1     1 1#.1
    ----------------------------------

Таблица умножения как для обычной сбалансированной троичной:

    ----------------------------------
    *   |      1#      0          1
    ----+-----------------------------
    1#  |      1       0          1#
    0   |      0       0          0
    1   |      1#      0          1
    ----------------------------------

Соответсвенно:

    1	1		t^0
    2	1 1#. 1		t^2 - t^0 + t^(-2)
    3	1 0 . 1		t^2 + t^(-2)
    4	1 1 . 1
    5	1 1# 1  . 1# 1
    6	1 0  1# . 0  1
    7	1 0  0  . 0  1
    8	1 0  1  . 0  1
    9	1 1  1# . 1  1
    10	1 1  0  . 1  1

Обратите внимание что целые числа являются симметричными относительно 0 разряда

            ось симметрии
            |
степень         2   1   0  -1 -2
        C   B   A.  B  C
                |

Кроме этого так как основа троичная сбалансированная система, то у -X просто
проинвертированы все триты.

    -1	1#
    -2	1#  1 .  1#
    -3	1#  0 .  1#
    -4	1#  1#.	 1#
    итд

И все операции производятся в прямом коде.

Пример сложения

    +	5 	0   1   1#   1  .  1#   1    0
    10      0   1   1    0  .  1    1    0
       ---------------------------------------
                           1    1#.  1
                   0
                 1
            0
        1   1#. 1
       ---------------------------------------
    15	1   1#  1    1  .  1    1#   1


3.11. ОПТИМАЛЬНАЯ СИСТЕМА СЧИСЛЕНИЯ

Пусть основание системы счистления = p, a число разрядов = n
тогда:

    можно представить N = p^n   различных чисел [0...(p^n)-1]

Пусть число N заданно (например 1000).
Для заданного N число разрядов (~ числу элементов для хранения):

    pn = p log{p}(N) = p / log{N}(p)

Вычисляем p/log{10}(p), для других N он будет пропорциональном

        p	p/log{10}(p)
    2	6.64
    3	6.29
    4	6.64
    5	7.15
    8	8.86
    12	11.12
    16	13.29

На графике представлена функция Exp(log{10}(x)/x):

Вывод: наиболее экономичная система счистления с основанием e (2.718)
       а из целых троичная (сбалансированная).

На пальцах:

    Числа 0...999	(всего 1000)
    В 10 системе надо 30 знаков = 3 разряда * 10 цифр
    В 2-ной системе из 30 знаков можно построить 2^15 > 1000 чисел

    Имеем ряд (для 60 знаков):

    2^30	3^20  4^15  5^12  6^10  10^6  12^5
        ----
        максимально


3.12. ПРЕДСТАВЛЕНИЕ ОТРИЦАТЕЛЬНЫХ ЧИСЕЛ В CЧ С НАТУРАЛЬНЫМ ОСНОВАНИЕМ.

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

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

  Прямой код

    Прямой код
    -----------
        старший разряд числа  показывает знак
        остальные разряды содержат число
            например
                0101	5 	{2, прям}
                1101	-5      {2, прям}

        для троичного случая (обычная троичная система):
                0101	10      {3, прям}
                1XXX	не используется
                2101	-10     {3, прям}

        для четверичной системы:
                0101	17	{4, прям}
                1101	81	{4, прям}
                2101	-81	{4, прям}
                3101	-17	{4, прям}

        для пятичной системы:
                0101	26	{5, прям}
                1101	151	{5, прям}
                2XXX	не используется
                3101	-151	{5, прям}
                4101	-26	{5, прям}

        Прямой код содержит два представления для 0
                0000	+0	{2, прям}
                1000	-0	{2, прям}
                - - - - -
                0000	+0	{3, прям}
                2000	-0	{3, прям}

        Пользоваться прямым кодом неудобно, т.к даже схема сложения
        должна учитывать знак числа:
        Например:  5 + 2
                0101	5	{2}
                  +	0010	2       {2}
                ---------
                0111	7	{2}

        но	   5 + (-2):
                0101	5	{2, прям}
                  + 1010	-2	{2, прям}
                ---------
                1111	-7	{2, прям}

        и даже
               5 + (-0)
                0101	5	{2, прям}
                1000	-0	{2, прям}
                ----------
                1101	-5	{2, прям}

        соответсвенно схемы для арифметических операций получаются
        сложными.

Кольцо для прямого кода (СЧ 2):

  Смещенный код

    Смещенный код
    -------------
        Рассмотрим двоичный случай
        Примем за 0 число вида 10..00
            Тогда отрицательные числа естественным образом меньше
            а положительные больше
        Пример:
            0000	-8
            0001	-7
            ...
            0111	-1
            1000	0   <----
            1001	1
            ....
            1111	7
        В троичном случае можем взять 1111 как базу
            1101	-3
            1102	-2
            1110	-1
            1111	0   <----
            1112	1
            1120	2
            1121	3
        Недостаток:
            положительные числа не совпадают с прямым кодом.

  Обратный код

    Обратный код
    -------------
        -X = NOT(X)
        т.е. отрицательное число - это инвертированное положительное
        Например двоичный случай:
                0101	5	{2, обр}
                1010	-5      {2, обр}

            В двоичном случае обратный код называют дополнением до 1
            (потому что если сложить X и -X в каждом разряде будет 1:
                0101    5       {2, обр}
                  + 1010    -5      {2, обр}
                  ------
                1111    -0      {2, обр}

        для троичного случая
                0101	10      {3, обр}
                2121	-10     {3, обр}

            Соответсвенно в троичном случае обратный код будет дополнением до 2
            (если сложить X и -X то в каждом разряде будет 2):
                0101	10	{3, обр}
                  + 2121    -10     {3, обр}
                  ------
                2222    -0      {3, обр}

        т.е. A + (-A) = P^N - 1, где P - основание системы счистления,
        а N - разрядность сетки представления чисел.

        Обратный код также как прямой содержит два представления для 0:
                0000	+0	{2, обр}
                1111	-0	{2, обр}
                - - - - -
                0000	+0	{7, обр}
                6666	-0	{7, обр}

        Обратным кодом тоже пользоваться неудобно,
        хотя	A + (-A) = - 0, но
                0101	5	{2, обр}
                  + 1111   -0       {2, обр}
                  ------
                        0100	4	{2, обр}

        и
                0101	5	{2, обр}
                  + 1110	-1	{2, обр}
                ----
                0011	3	{2, обр}

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

Кольцо для обратного кода (СЧ 2):

  Дополнительный код

    Дополнительный код
    -------------------
        -X = NOT(X) + 1
        таким образом:  A + (-A) = P^N
        что упрощаяет контруирование сумматоров (т.к. и сложение и
        вычитание чисел можно производить на одном и том же оборудовании).

        для двоичного случая:
            X	01100	12	{2}
                NOT(X)	10011		{2}
            -X	10100	-12	{2, доп}

            проверим:
                   |01100|
                +  |10100|
             --------------
                  1|00000| - получаем в результате 0.

            поэтому двоичный случай еще называют дополнением до двух.

        теперь для троичного случая:
            X	0101	10	{3}
            NOT(X)  2121
            -X	2122	-10	{3, доп}

            проверяем:
                   |0101|
                 + |2122|
              -----------
                  1|0000|  - получаем в результате 0
            дополнительный код в троичномм случае является дополнением до 3

        дополнительный код содержит только один 0 - который имеет вид:
            000...0000	(все разряды равны 0)

        отрицательные числа имеют вид
            1xx...xxxx
        положительные числа имеют вид
            0xx...xxxx

        дополнительный код (мы сейчас рассмотрим только двоичный случай)
        имет одно исключительное число вида
            100...0000	(старший бит = 1, остальные 0),
        это число -2^(N-1), где N - разрядность сетки
                1000		-8  	{2, доп}
            10000000        -128	{2, доп}
        положительное число с таким же модулем не представимо в сетке
        и мы получаем:
            X	1000
            NOT(X)	0111
            -X	1000
        т.е. специальный случай, когда -X = X
        a все остальное хорошо: для сложения простая схема,
        0 только один - поэтому в наше время для пресдставления
        отрицательных чисел используется практически исключительно\
        дополнительный код.

Кольцо для дополнительного кода (СЧ 2):

  Сравнение кодов

    -------------------------------------------------------
        sign    1's        2's
           magnitude complement complement
    -------------------------------------------------------
        Прямой 	Дополнение Дополнение
        код	до 1	   до 2
    -------------------------------------------------------
        Прямой  Обратный   Дополнительный   Смещенный
        код	код	   код              код
    -------------------------------------------------------
    0111	+7	+7	   +7               -1
    0110    +6      +6         +6               -2
    0101    +5      +5         +5               -3
    0100    +4      +4         +4               -4
    0011    +3      +3         +3               -5
    0010    +2      +2         +2               -6
    0001    +1      +1         +1               -7
    0000    +0      +0         0 		    -8
    1000    -0      -7	   -8               0
    1001    -1      -6         -7               +1
    1010    -2      -5         -6               +2
    1011    -3      -4         -5               +3
    1100    -4      -3         -4               +4
    1101    -5      -2         -3               +5
    1110    -6      -1         -2               +6
    1111    -7      -0         -1               +7
    -------------------------------------------------------

    ------------------------------------------
    Число	Прямой	Обратный Дополнительный
    ------------------------------------------
    +7	0111	0111	0111
    +6	0110	0110	0110
    +5	0101	0101	0101
    +4	0100	0100	0100
    +3	0011	0011	0011
    +2	0010	0010	0010
    +1	0001	0001	0001
    +0	0000	0000	0000
    -0	1000	1111	----
    -1	1001	1110	1111
    -2	1010    1101    1110
    -3	1011    1100    1101
    -4	1100    1011    1100
    -5	1101    1010    1011
    -6	1110    1001    1010
    -7	1111    1000    1001
    -8	----    ----    1000
    ------------------------------------------

  Арифметика в дополнительном коде

Пример кольца двоичных чисел:

Сложение:

Вычитание:

Переполнение:

Флаги:

CF (Carry Flag)
    флаг переноса
    устанавливается если проходим через границу 00..00/11..11
    т.е. когда происходит перенос/заем в/из границы адрессной сетки
    (беззнаковое переполнение)

OF (Overflow Flag)
    флаг переполнения
    устанавливается если проходим через границу 01..11/10..00
    т.е. когда не умещаемся в отрицательные или положительные числа
    в пределах нашей сетки
    (знаковое переполнение)

ZF (Zero Flag)
    флаг нуля
    устанавливается если результат равен нулю.

  Арифметика с насышением

Арифметика с насышением:

Результат не может перейти границу переполнения
В этом случае он устанавливается равным границе.

        Арифметика с
        насыщением
        /	  \
    Знаковая	Беззнаковая
    Signed		Unsigned
    Saturation	Saturation

      8E		  C0
    + 8E            + C0
    ----		----
      80              FF

      7F		  C0
    + 7F		- F0
    ----		----
      7F	          00


3.13. КОМПЛЕКСНЫЕ ЧИСЛА

Обобщение линии действительных чисел на плоскость.
Идея - перпендикулярное к действительной оси направление определяется
корнем из -1 (не имеет рашений в действительных числах)

Запись	{a,b} - означает   а + b*i, где i - квадратный корень из (-1)
так называемая мнимая единица

i - корень уравнения	X^2 + 1 = 0

    т.к. (a + b) * (a - b) = a^2 + ab - ab - b^2 = a^2 - b^2
    то мы можем разложить X^2 + 1

    X^2 + 1 = (X + i)*(X - i) = 0

    корни  i и -i

Действительные числа - частный случай комплексных.

  Сложение и вычитание

{a1, b1} + {a2, b2}  = {a1 + a2, b1 + b2}
{a1, b1} - {a2, b2}  = {a1 - a2, b1 - b2}

  Умножение

{a1, b1} * {a2, b2}  = {a1*a2 - b1*b2, b1*a2 + a1*b2}

  Деление

{a1, b1} / {a2, b2} = { (a1*a2+b1*b2)/(a2^2+b2^2), (b1*a2-a1*b2)/(a2^2+b2^2) }

 a + b*i     a + b*i     c - d*i     a*c + b*d      b*c - a*d
--------- = --------- * --------- =  ----------  + ----------- i
 c + d*i     c + d*i     c - d*i     c^2 + d^2     c^2 + d^2

  Тригонометрическая форма

Число представляется в виде:
    a + bi

    r = sqrt(a^2 + b^2)
    a = r cos Ф
    b = r sin Ф

  Возведение в степень

[ r (cos Ф + i*sin Ф) ]^n = r^n [cos(nФ) + i*sin(nФ) ]

e^(i*x) = cos(x) + i*sin(x)

Пример корней 4 степени из 1:

Комплексные числа широко используются в электроннике.

    ln(-1)   = i*PI
    ln(2)    = ln(2) + i*PI
    ln(-1/2) = -ln(2) + i*PI


3.14. ПРОСТРАНСТВЕННЫЕ КОМПЛЕКСНЫЕ ЧИСЛА

По аналогии с плоскостью можем обобщить комплексные числа в объем.

Пространственное комплексное число:

    A + B*j	, где A и B - комплексные числа.

т.е:
    (a1 + a2*i) + (b1 + b2*i)*j

i,j - мнимые единицы,  корни уравнения X^2 + 1 = 0

    X^2 + 1 = 0              	уравнение
    (X + i) * (X - i) = 0		см. предидущую секцию

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

Вводим новую мнимую единицу j - которая не принадлежит множеству комплексных
чисел, но для которой:  (j + i) * (j - i) = 0
Сомножители (j + i) и (j - i) - называются делителями нуля.
(Строго говоря делители нуля - это целые прямые).

Таким образом квадратное уравнение X^2 + 1 = 0 имеет 4 корня:

        i	-i
        j	-j

Таблица умножения для мнимых единиц:

    i*i = -1
    j*j = -1

    i*j = k		(k - это такое пространственное комплексное число)
    j*i = k

    k*k = 1 	(k - корень уравнения X^2-1 = 0, корень отличный от 1 и -1)

    (i+j)*(x-j) = 0

таким образом уравнение X^2 - 1 = 0 имеет 4 корня

        1	-1
        k =ij	k = -ij

  Сложение и вычитание

    {A1, B1} + {A2, B2} = {A1 + A2, B1 + B2}
    {A1, B1} + {A2, B2} = {A1 - A2, B1 - B2}

  Умножение

    {A1, B1} * {A2, B2} = {A1*A2-B1*B2, A1*B2 + B1*A2}

Делить на 0 нельзя, также как нельзя делить на делители нуля.

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


3.15. ЗОЛОТОЕ СЕЧЕНИЕ

Золотое сечение - гармоническое деление отрезка на 2 части так что

    a       x
       --- = -------
    x     a - x

            a
    +------------------+
    +-------+----------+
    +-------+
            x

откуда           +   ----
               1 -  V  5
    x = - ------------- a
               2

Это было золотое сечение 1го порядка
Золотое сечение бывает и других порядков:

     (a/x)^S = x/(a - x)

    --------------------------------------------
    S	0  	1    	2    	3    	4
    --------------------------------------------
    X       0.5     0.618   0.683   0.725  0.755
    --------------------------------------------

Золотое сечение связано с числами Фибоначи соотношением:

                    _
         Ф^n  - Ф^n
    Fn = -----------
          sqrt(5)

где

             1 + sqrt(5)
    Ф = -------------
        2

        _    1 - sqrt(5)
    Ф = -------------
        2

Доказательство по индукции:
                _
пусть Ф^n = a,  Ф^n = b.

тогда

    Fn = (a + b) / sqrt(5)   =  (2a + 2b) / (2sqrt(5))

    Fn+1 = (1 + sqrt(5)) a - (1 - sqrt(5)) b
           ----------------------------------
            2 sqrt(5)

    Fn+2 = (1 + 2sqrt(5) + 5) a - (1 - 2sqrt(5) + 5) b
           ------------------------------------------- =
            4 sqrt(5)

        =  (6 + 2sqrt(5)) a - (6 - 2sqrt(5)) b
        ----------------------------------  =
            4 sqrt(5)

       =  (3 + sqrt(5))a - (3 - sqrt(5))b
          --------------------------------
            2 sqrt(5)

Должно выполняться равенство:

    Fn+2 = Fn+1 + Fn

домножим обе части на 2sqrt(5)
получаем:

    (3 + sqrt(5)) a - (3 - sqrt(5) b = (1 + sqrt(5)) a - (1 - sqrt(5) b +
                       2a + 2b

получаем тождество.
Теперь проверим для первых членов ряда:

    F{0} = 0 = 1 - 1   = 0
           -------
           sqrt(5)

    F{1} = 1 =  1 + sqrt(5) - (1 - sqrt(5))  = 2sqrt(5) = 1
           --------------------------      --------
            2 sqrt(5)	           2sqrt(5)

    F{2} = 1 = 1 + 2sqrt(5) + 5 - (1 - 2sqrt(5) + 5)   4sqrt(5)
               ------------------------------------- = -------- = 1
                4sqrt(5)                   4sqrt(5)

Соответственно по индукции форула верна и для других n.


3.16. НЕМНОГО ОБЩЕЙ АЛГЕБРЫ

  Группа

Def
===
    Множество G с заданной на нем бинарной операцией @ назовем ГРУППОЙ
    если выполняются следующие аксиомы:

    1) Ассоциативность
       Для любых a,b,c из G:
        (a @ b) @ c = a @ (b @ c)
    2) Наличие нейтрального элемента
       В G существует элемент е такой, что для всех a в G
        e @ a = a @ e = a
    3) Наличие обратного элемента
       для любого a из G есть обратный элемент b такой, чтo
        a @ b = b @ a = e

    (Если выполняются только первые 2 аксиомы то такое множество
     называется МОНОИДОМ)

Def
===
    Если группа еще и коммутативна
    т.е. для всех a,b из G
        a @ b = b @ a
    то такая группа называется АБЕЛЕВА ГРУППА

  Кольцо

Def
===
    Множество G c заданными на нем бинарными операциями '+' и '*'
    называется КОЛЬЦО если выполняются следующие аксиомы:

    1) Коммутативность по сложению
       для любого a,b в G
        a + b = b + a
    2) Ассоциативность по сложению
       для любого a,b,c в G
        a + (b + c) = (a + b) + c
    3) Наличие нейтрального элемента по сложению (нуля)
       В G существует элемент 0 такой, что для всех a в G
        a + 0 = 0 + a = a
    4) Дистрибутивность
       для любых a,b,c в G
        a * (b + c) = b * a + c * a

    Дополнительные свойства возможные у колец:
    5) Коммутативность по умножению
       для любого a,b в G
        a * b = b * a
    6) Ассоциативность по умножению
       для любого a,b,c в G
        a * (b * c) = (a * b) * c
    7) Наличие нейтрального элемента по умножению (единицы)
       В G существует элемент 0 такой, что для всех a в G
        a * 1 = 1 * a = a
    8) Отсутствие делителей нуля
       для любого a,b в G
       если  a * b = 0
       то как минимум либо a = 0, либо b (либо оба)

Примеры колец:
    Z  - целые числа
    Zn - кольцо вычетов по модулю натурального числа n
    R[x1,...,xn] - кольцо многочленов от n переменных над полем R

  Тело

Def
===
    Ассоциативное по умножению кольцо с 1 (т.е (6)+(7)) в котором каждый
    ненулевой элемент обратим
    т.е для любого ненулевого a из G - существует ненулевой b из G
    такой что
        a * b = b * a = 1
    называется ТЕЛОМ

Пример тел:
    Квадратные матрицы
    Кватернионы

  Поле

Def
===
    Коммутативное (5) тело называется ПОЛЕМ

Примеры полей
    Q - рациональные числа
    R - вещественные числа
    С - комплексные числа
    Zp - поле вычетов по модулю p, где p - простое число
    Fq - конечное поле из q = p^k элементов где p - простое число,
         a k - натуральное


3.16.1. КВАДРАТНЫЕ МАТРИЦЫ

    Умножение на скаляр:
        С = n * A
        C{i,j} = n*A{i,j}

    Сложение:
        C = A + B
        C{i,j} = A{i,j} + B{i,j}

    Вычитание:
        C = A - B
        C{i,j} = A{i,j} - B{i,j}

    Умножение:
        C = A * B
        C{i,k} = SUM{по j} [A{i,j} * B{j,k}]
        Умножение не коммутативно
        т.е. AB != BA

        A = | 0 1 |		B = | 0 0 |
            | 0 0 |                 | 1 0 |

        A*B = | 1 0 |		B*A = | 0 0 |
              | 0 0 |                 | 0 1 |
        но
            A(BC) = (AB)C
            A(B+C) = AB + AC
            (B+C)D = BD + CD

    Нулевая матрица
        A + 0 = A = 0 + A
        A + (-A) = 0 = (-A) + A
        A * 0 = 0
        все элементы нули
        | 0 0 0 |
        | 0 0 0 |
        | 0 0 0 |

    Единичная матрица:
        I * A = A * I = 1

        Имеет вид:
        единицы на главной диагонали, остальное нули

        | 1 0 |		| 1 0 0 |      	| 1 0 0 0 |
        | 0 1 |         | 0 1 0 |       | 0 1 0 0 |
                        | 0 0 1 |       | 0 0 1 0 |
                                        | 0 0 0 1 |
    Обратная матрица:
        A * A^-1 = I	(существует не всегда)

        | 1 1 |^-1     | 0  1 |
        | 1 0 |     =  | 1 -1 |

        (BA)^-1 = A^-1 * B^-1

        (A^-1)^T = (A^T)^-1

    Вырожденная матрица
        матрица не имеющая обратной

    Транспонированная матрица
        меняются местами строки и столбцы
        A^T
        C{i,j} = A{j,i}

        | 1 2 3 |T      | 1 4 |
        | 4 5 6 |    =  | 2 5 |
                        | 3 6 |

    Симметрическая матрица
        A^T = A

        | 1 2 3 |
        | 2 6 4 |
        | 3 4 5 |

    Минор элемента a{i,j} матрицы A(nxn) - матрица (n-1)x(n-1) получаемая
    вычеркивание из матрицы A i-й строки и j-того столбца.
    обозначается как A[i,j]

    Определитель:

    det(A) =  a{1,1} если n=1,
          a{1,1}*det(A[1,1]) - a{1,2}det(A[1,2]) + ...
            + (-1)^(n+1)*a{1,n}det(A[1,n]), если n>1

    det(AB) = det(A)det(B)

    Квадратная матрица A являестсы вырожденной тогда и только тогда
    когда det(A) = 0.

    И снова обратная матрица:
                      | D{1,1} D{1,2} D{1,3} |
    A^-1 = 1/det(A) * |               ..     |
                | D{3,1}  ....  D{3,3} |

    где  D{i,j} - алгебраические дополнения элементов a{i,j} исходной
    матрицы.

    D{i,j} = (-1)^(i+j) * det(A[i,j])


3.16.2. ВЕКТОРНАЯ АЛГЕБРА

Def
===
    ВЕКТОР - это направленный отрезок

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

    Длинна вектора - это длинна соответствующего отрезка.

  Сложение

        ->                      ->
        a  = { x1, y1, z1 }	b  = { x2, y2, z2 }

        ->  ->
        a + b  = { x1+x2, y1+y2, z1+z2 }

  Вычитание

        ->  ->
        a - b  = { x1-x2, y1-y2, z1-z2 }

  Скалярное произведение

            -> ->    -> ->
        a  b  = |a| |b| cos Ф

    для декартовых координат
        ->                      ->
        a  = { x1, y1, z1 }	b  = { x2, y2, z2 }

        ->  ->
        a * b  = x1*x2 + y1*y2 + z1*z2

  Векторное произведение

    Результат векторного произведение векторов  -  вектор который имеет длинну
                  -> ->
        R  = |a| |b| sin Ф

        ортогонален векторам a и b
        и тройка abc является правой.

    для декартовых координат
        ->                      ->
        a  = { x1, y1, z1 }	b  = { x2, y2, z2 }

        ->  ->
        a X b  = { y1*z2 - y2*z1, z1*x2 - z2*x1, x1*y2 - x2*y1 }

        ->  ->       |  i   j  k  |
        a X b  = det | x1  y1 z1  |
                 | x2  y2 z2  |

Операция верторного умножения не является коммутативной:
    т.е.
            ->  ->       ->   ->
        a x b   !=   b  x a    (в общем случае)


3.16.3. КВАТЕРНИОНЫ

Система гиперкомплексных чисел
(Умножение не коммутативно:
 Кватернионы - это не пространственные комплексные числа)

    пара  Вектор-Скаляр

        ->
    (a, u  )

         ->        ->             ->  ->
    (a , u ) + (b, v)  = ( a + b, u + v )

                 ->        ->                  ->
    (a, 0) * (0, v ) = (0, v ) * (a, 0) = (0, av )

    (a, 0) * (b, 0) = (ab, 0)

        ->       ->     -> ->  ->  ->
    (o, u) * (0, v) = ( -u v , v X u )

Матрично кватернионы - комплексные матрицы вида

    |   a        b   |
    |                |
    |   _        _   |        _
    |  -b        a   |,  где  a - это число комплексно сопряженное с а
c обычными правилами для матричных сумм и произведений.

Кватернионы можно представить в виде

    a + b*i + c*j + dk,  где i,j,k - корни из 1
    --  --------------
Скалярная   Векторная часть
часть

    *  |  1   i   j   k
    ---+----------------
    1  |  1   i   j   k
        i  |  i  -1   k  -j
        j  |  j  -k  -1   i
        k  |  k   j  -i  -1

Сложение
    a1 + b1*i + c1*j + d1*k
  +     a2 + b2*i + c2*j + d2*k =
    (a1+a2) + (b1+b2)*i + (c1+c2)*j + (d1+d2)*k

Умножение
    (a1*a2 - b1*b2 - c1*c2 - d1*d2) +
    (a1*b2 + b1*a2 + c1*d2 - d1*c2)*i +
    (a1*c2 + c1*a2 - b1*d2 + d1*b2)*j +
    (a1*d2 + d1*a2 - b1*c1 - c1*b2)*k

              ->                      ->
    q1 = x1 + r1		q2 = x2 + r2

                   -> ->        ->      ->   ->   ->
    q1q2 = (x1x2 - r1*r2) + (x1*r2 + x2*r1 + r1 X r2)

Деление:
    поскольку тело, то  не коммутативно
    соответсвенно
        b  * c = a
        c' * b = a


3.16.4. НЕМНОГО ТЕОРИИ ЧИСЕЛ

  Простые числа

Def
===
    Число называется ПРОСТЫМ если оно имеет только 2 делителя единицу и
    само себя. (1 не считается простым числом).

Решето Эратосфена:

       2  3  X  5  X  7  X  X  X
        11 X 13  X  X  X 17  X 19  X
     X X 23  X  X  X  X  X 29  X
    31 X  X  X  X  X 37  X  X  X
    41 ...

  НОД и НОК

    m \ n = значит m делит n

наибольший общий делитель:
    hcf	highest common factor		(UK)
    gcd	greatest common divisor		(US)

    НОД(m,n) = MAX(k | k\m и k\n )

Алгоритм Евклида:
    НОД(0, n) = n
    НОД(m, n) = НОД(n mod m, m)   при m > 0

наименьшее общее кратное:
    НОК(m,n) = MIN(k | k>0, m\k, n\k)

  Остаток от деления

Остаток от деления

    x mod y = x - y| x/y |
                   +-   -+
                  целая часть - округление к низу

    5 mod 3   = 2         = 5 - 3 * ROUND_LOW(5/3)     = 5 - 3*1 = 2
    5 mod -3  = -1        = 5 - (-3) * ROUND_LOW(5/-3) = 5 - (-3)*(-2) = 5-6 = -1
    -5 mod 3  = 1	      = -5 - 3 * ROUND_LOW(-5/3)   = -5 - (-3)*2   = 5+6 = 1
    -5 mod -3 = -2	      = -5 - (-3)*ROUND_LOW(-5/-3) = -5 - (-3)*1   = 5+3 = =-2

    c (x mod y) = (cx) mod (cy)


3.16.4.1. КОЛЬЦА ВЫЧЕТОВ

Пример по модулю 3:

Zn
множество Z = Цифры: {0,1,...,n-1}  по модулю n
все действия осуществляются по модулю n.

Пример по модулю 6:

     +| 0 1 2 3 4 5
    --+-------------
     0|	0 1 2 3 4 5
     1| 1 2 3 4 5 0
     2|	2 3 4 5 0 1
     3|	3 4 5 0 1 2
     4|	4 5 0 1 2 3
     5|	5 0 1 2 3 4

     *| 0 1 2 3 4 5
    --+-------------
     0|	0 0 0 0 0 0
     1|	0 1 2 3 4 5
     2|	0 2 4 0 2 4
     3|	0 3 0 3 0 3
     4|	0 4 2 0 4 2
     5|	0 5 4 3 2 1

Пример по модулю 8

     +| 0 1 2 3 4 5 6 7
    --+-----------------
     0|	0 1 2 3 4 5 6 7
     1|	1 2 3 4 5 6 7 0
     2|	2 3 4 5 6 7 0 1
     3|	3 4 5 6 7 0 1 2
     4| 4 5 6 7 0 1 2 3
     5| 5 6 7 0 1 2 3 4
     6| 6 7 0 1 2 3 4 5
     7| 7 0 1 2 3 4 5 6

     *| 0 1 2 3 4 5 6 7
    --+-----------------
     0|	0 0 0 0 0 0 0 0
     1|	0 1 2 3 4 5 6 7
     2|	0 2 4 6 0 2 4 6
     3|	0 3 6 1 4 7 2 5
     4|	0 4 0 4 0 4 0 4
     5|	0 5 2 7 4 1 6 3
     6|	0 6 4 2 0 6 4 2
     7|	0 7 6 5 4 3 2 1

Законы арифметики в кольцах вычетов:

Коммутативные:
    (w+x) mod n = (x+w) mod n
    (w*x) mod n = (x*w) mod n

Ассоциативные:
    [(w+x)+y] mod n = [w + (x+y)] mod n
    [(w*x)*y] mod n = [w * (x*y)] mod n

Дистрибутивный:
    [(w+x)*y] mod n = [(w*y)+(x*y)] mod n

Тождества:
    (0+w)  mod n = w mod n
    (1*w)  mod n = w mod n

Для любого w, существует такое z, что w+z = 0 mod n

Если  (a+b) = (a + c) mod n,   то  b = c  mod n

Если  (a*b) = (a*c) mod n, то b = c mod n, только если a и n - взаимно простые
числа.

Пример:
    6*3 = 18 = 2 mod 8
    6*7 = 42 = 2 mod 8


3.17.1. ПОЛЯ ГАЛУА GF[p]

Zp - если p - простое, то все элементы Zp будут взаимо просты с p.
И тогда
    для любого ненулевого w в Zp существует такое z, что w*z = 1 mod p
    (условие для Поля Галуа).

Попробуем подсчитать для простого числа
НАПРИМЕР 7:

Btw, Это поле является полем Галуа GF[7] = GF[7,1].

сложение по модулю 7:
     + | 0 1 2 3 4 5 6
    ---+--------------
     0 | 0 1 2 3 4 5 6
     1 | 1 2 3 4 5 6 0
     2 | 2 3 4 5 6 0 1
     3 | 3 4 5 6 0 1 2
     4 | 4 5 6 0 1 2 3
     5 | 5 6 0 1 2 3 4
     6 | 6 0 1 2 3 4 5

умножение по модулю 7:
     * | 0 1 2 3 4 5 6
    ---+--------------
     0 | 0 0 0 0 0 0 0
     1 | 0 1 2 3 4 5 6
     2 | 0 2 4 6 1 3 5
     3 | 0 3 6 2 5 1 4
     4 | 0 4 1 5 2 6 3
     5 | 0 5 3 1 6 4 2
     6 | 0 6 5 4 3 2 1

найдем отрицательные и обратные величины:
    w  -w  w^(-1)
       --------------
    0  0	-
    1  6    1
    2  5    4
    3  4    5
    4  3    2
        5  2    3
    6  1    6

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

для этого попробуем посчитать степени элементов:

                 a
    a^N | 1  2  3  4  5  6
    ----|-------------------
      1 | 1  2  3  4  5  6
      2 | 1  4  2  2  4  1
       N  3 | 1  1  6  1  6  6
      4 | 1  2  4  4  2  1
      5 | 1  4  5  2  3  6
      6 | 1  1  1  1  1  1
              ^
                  |
                          +--- вот он примитивный элемент

Теорема Ферма (малая теорема Ферма):
    Если p - простое, а  a - положительное целое, то
        a^(p-1) = 1 mod p
        a^p = a mod p

таблица степеней:
    элемент 5 - примитивный
    его степенями можно представить любой другой ненулевой элемент

    5^1 = 			5
    5^2 = 25 mod 7 = 	4
    5^3 = 125 mod 7 = 	6
    5^4 = 625 mod 7 =	2
    5^5 = 3125 mod 7 =	3
    5^6 = 15625 mod 7 = 	1

Дискретные логарифмы:

      --------------------------------------------
        w	5^N	5^N    5^N	5^N
      --------------------------------------------
        5	1	7	-5	-11
        4       2       8	-4      -10
        6       3       9	-3      -9
        2       4       10	-2      -8
        3       5       11	-1      -7
        1       6	12	0       -6
      --------------------------------------------

умножение - это сложение индексов
    X^i * X^j =  X^(i+j)

деление   - вычитание индексов
    X^i / X^j =  X^(i-j)
    на ноль делить нельзя

дискретное логарифмирование
    log N = log(X^i) = i

    Умножение:
        3 * 4 = 12 mod 7 = 5
        3 * 4 = 5^5 * 5^2 = 5^(5+2) = 5^7 = 5

    Деление:
        6 / 2 = 5^3 / 5^4 = 5^(3-4) = 5^(-1) = 3
        6 / 3 = 5^3 / 5^5 = 5^(3-5) = 5^(-2) = 2
    но зато 6 / 4 = 5^3 / 5^2 = 5^(3-2) = 5^1    = 5
        проверим
            5 * 4 = 20 mod 7 = 6  все верно

        6 / 1 = 5^3 / 5^6 = 5^(3-6) = 5^(-3) = 6
        6 / 5 = 5^3 / 5^1 = 5^(3-1) = 5^2    = 4
        5 / 3 = 5^1 / 5^5 = 5^(1-5) = 5^(-4) = 4
        2 / 2 = 5^4 / 5^4 = 5^0     =          1


3.17.2. ПОЛИНОМАЛЬНАЯ АРИФМЕТИКА

Рассмотрим полиномальную арифметику на классах вычетов:

  Сложение

        каждый разряд отдельно в пределах поля S{n} = Zn без переноса
        для S{2} это {0,1} а операция XOR:
        (причем и для сложения и для вычитания).

        а для S{3} это {0,1,2} - будет сложение по модулю 3
        (сложение и вычитание дают разные результаты).

        Например по модулю 2:

            X^3 + X^2 + X + 1		1111
           +    X^3 +           1          XOR  1001
          -----------------------               ----
                  X^2 + X			 110

            X^3 + X^2 + X + 1		1111
           -    X^3 +           1          XOR  1001
          -----------------------               ----
                  X^2 + X			0110

        А теперь по модулю 3:

            X^3 + X^2  + X + 1		1111
          +     X^3 + 2X^2 +     1           +  1201
         -------------------------              ----
               2X^3 +      + X + 2		2012

            X^3 + X^2  + X + 1		1111
          -     X^3 + 2X^2 +     1           -  1201
         -------------------------              ----
                      2X^2 + X			0210

  Умножение

    Умножение - как мы и умножали в школе полиномы (но с учетом
            правил сложения)

        A = a{i}*x^i + ... + a{1}*x^1 + a{0}*X^0
        B = b{i}*x^i + ... + b{1}*x^1 + b{0}*X^0

        A*B = SUM{i,j} (  a{i}b{j}*x^(i+j) )

        Пример
            (X^2 + X + 1) * (X^2 + X + 1) =
                    X^2 +  X + 1
            +         X^3 + X^2 +  X
            +   X^4 + X^3 + X^2
            =   X^4 + (2*X^3) + (3*X^2) + 2*X +1
        Если S{2}
              (1 mod 2)*X^4 + (2 mod 2)*X^3 + (3 mod 2)*X^2 +
              (2 mod 2)* X  + 1	=
            =  1*X^4 + 0*X^3 + 1*X^2 + 0*X^2 + 1
                =  1*X^4 + 1*X^2 + 1
            = X^4 + X^2 + 1
                     111
                                   * 111
                       -----
                     111
                                +   111
                                   111
                                   ------
                       10101
                  Если срубить по разрядной сетке: то X^2 + 1  (101)

        Если S{3}
              (1 mod 3)*X^4 + (2 mod 3)*X^3 + (3 mod 3)*X^2 +
              (2 mod 3)*X  + 1  =
               =  1*X^4 + 2*X^3 + 0*X^2 + 2*X + 1
               =  X^4 + 2X^3 + 2X + 1
                     111
                   * 111
                 -------
                     111
                                +   111
                                   111
                                 -------
                   12021
              Если срубить по разрядной сетке: то 2X + 1 (021)

               Частный пример:
                2*X^2 + 1 		201
              *		2            *    2
            -----------------            ------
                 X^2 + 2		102

  Остаток от деления

Остаток от деления на полином:

    например для S{2}  есть полином X^2+1  (101)
    что такое арифметика по модулю этого полинома.
    Остаток должен иметь степень меньшую чем полином например
        X+1	11	так и будет 	11
        X^2 + X + 1 (111) будет
                111
            XOR	101	= 10
                ----
                 10

        X^4 + X^3 + X     (11010)
                11010
                101
                 111
                 101
                  100
                  101
                  ---
                       01

    Теперь рассмотрим S{3}. Пусть есть полином 2X^2 + X + 2 (212)
    Остаток должен иметь степень меньшую чем полином например
        2X + 1  (21) так и будет 21
    а
        X^2 + X + 1 (111) будет
            111			(212 * 2 =  121)
               -121
            ---
                 20  = 20

        X^4 + X^3 + 2*X^2 + X + 2  (11212)

                 11212
               -121
                -----
                 211
                -212
                -----
              022 = 22

    Для S{2} и S{3} - все ОК.
    Но попробуйте на S{4} по модулю 2X^2 + X + 3 (213) например
        представить  X^2 + X + 1 (111)
            213 * 1 = 213
            213 * 2 = 022  -> от степени X^2 таким полиномом не
                      избавимся.
    так что полином надо будет выбирать с коэффициентом 1 при старшей степени
        например  X^2 + X + 3  (113)
        тогда   X^2 + X + 1 (111) будет 02 по модулю X^2+X+3 S{4}
            111
               -113
            ---
             02   =  2 * X^0
        a  3*X^2 + 2X + 3  (323) будет
            323
           -    331     			(113 * 3 = 331)
            ---
             32   = 3X + 2

  Неприводимые и примитивные полиномы.

Многочлен f(x) c коэффициентами из поля K называется НЕПРИВОДИМЫМ
над K если не существует двух таких полиномов f1, f2 из К[x] степени не ниже первой
таких что f = f1 * f2

ПРИМИТИВНЫЙ полином степени N - это неприводимый полином степени n,
который делит
    X^k - 1, где k = p^n - 1
но не делит
    X^d - 1, для любого d, которое делит (p^n - 1)
Такой полином что-то типа простого числа над полем полиномов.
откуда берется примитивный полином:
из малая теорема Ферма:

        a^(p-1) = 1 mod p

    X^(p^n - 1) = 1		это как раз оно

для двоичных полиномов в литературе любят писать:

    x^k + 1,	x^d + 1

на самом же деле это просто вырожденный случай - вычеты по 2 им все равно
(-1 = 1), а уже начиная с троичного случая все по взрослому.
А люди до конца не понимают принципов лежащих в основах.

Примеры:

Например возьмем степени 3 над полем вычетов по 2:

    --------------------
    Полином	  Множители
    --------------------
    -1000	= 10  * 100
    -1001   = 111 * 11
    -1010	= 101 * 10
     1011	неприводимый
    -1100	= 11  * 100
    -1110	= 111 * 10
    -1111	= 11  * 101
    --------------------

доказательство неприводимости:
    полином степени 3 = полином степени 3 * полином степени 0
    полином степени 3 = полином степени 2 * полином степени 1 <- этот вариант
    полином степени 3 = полином степени 1 * полином степени 2 (см выше)
    полином степени 3 = полином степени 0 * полином степени 3 (см выше)

    полином степени 2 * полином степени 1 =
    ---------------------
    1xx * 1xx  Результат
    ---------------------
    100 * 10 = 1000
    100 * 11 = 1100
    101 * 10 = 1010
    101 * 11 = 1111
    110 * 10 = 1100
    110 * 11 = 1010
    111 * 10 = 1110
    111 * 11 = 1001
    --------------------
все остальные полиномы очевидно - неприводимые.

Рассмотрим наш неприводимый полином 1011:

он делит X^[ p^n - 1 ] - 1

     X^[ 2^3 - 1 ] - 1
     X^[ 8 - 1] -1
     X^7 - 1
     X^7 + 1

    10000001		X^7-1
    1011
    ------
      1100
      1011
          -----
       1110
       1011
           -----
        1011	ok
        1011
        ----
           0

(p^n - 1) = 7 - это простое число - у него нет делителей
значит X^d - 1 рассматривать не надо.
следовательно наш полином - 1011 - является примитивным.

Некоторые Примитивные полиномы на S{2}:
    ------------------------------------
    1	X   + 1
    2	X^2 + X   + 1
    3	X^3 + X   + 1
    4	X^4 + X   + 1
    5	X^5 + X^2 + 1
    6	X^6 + X   + 1
    7 	X^7 + X^3 + 1
    8	X^8 + X^4 + X^3 + X^2 + 1
    9	X^9 + X^4 + 1
    10	X^10 + X^3 + 1
    11	X^11 + X^2 + 1
    12	X^12 + X^6 + X^4 + X + 1
    13	X^13 + X^4 + X^3 + X + 1
    14	X^14 + X^10 + X^6 + X + 1
    15	X^15 + X + 1
    16	X^16 + X^12 + X^3 + X + 1
    ------------------------------------
(в таблице представленны не все примитивные полиномы, для некоторых степеней
их бывает больше 1).

Неприводимые трехчлены и пятичлены

    -----------------------------------
    n       коэффициенты (кроме n и 0)
    -----------------------------------
    2	1
    3	1
    4	1
    5	2
    6	1
    7	1
    8	7,3,2
    9	1
    10	3
    11	2
    12	3
    13	4,3,1
    14	5
    15	1
    16	5,3,1
    17	3
    18	3
    19	5,3,1
    20	3
    21	2
    22	1
    23	5
    24	8,3,2
    25	3
    26	4,3,1
    27	5,2,1
    28	1
    29	2
    30	1
    31	3
    32	7,3,2
    33	10
    -----------------------------------

Например для 5й степени примитивные полиномы:
    -------------------------------------
    100101	X^5 + X^2 + 1
    101111	X^5 + X^3 + X^2 + X + 1
    110111	X^5 + X^4 + X^2 + X + 1
    --------------------------------------

А теперь степени 2 над полем вычетов по 3.

    -----------------------------
        -100	= 10 * 10
     101	неприводимый
        -102	= 21 * 22 = 11 * 12
    -110	= 11 * 10
    -111	= 12 * 12
     112	неприводимый
    -120	= 12 * 10
    -121	= 11 * 11
     122	неприводимый = 211 * 2
    -200	= 10 * 20
    -201	= 21 * 11  = 22 * 12
     202	неприводимый = 101 * 2
    -210	= 21 * 10
     211    неприводимый
    -212    = 22 * 11
    -220	= 22 * 10
     221 	неприводимый
    -222	= 21 * 12
    -----------------------------

доказательство неприводимости:
    полином степени 2 может получиться только как:
        полином степени 2 * полином степени 0
        полином степени 1 * полином степени 1 -> нам нужен только этот случай
        полином степени 0 * полином степени 2

понятное дело нам нужны полиномы с ненулевым коэффициентом при 2 степени
таким образом рассматриваем:
    1x * 1x
    1x * 2x
    2x * 2x

смотрим:
    10 * 10 =  100
    10 * 11 =  110
    10 * 12 =  120
    10 * 20 =  200
    10 * 21 =  210
    10 * 22 =  220
    11 * 11 =  121
    11 * 12 =  102
    11 * 20 =  220
    11 * 21 =  201
    11 * 22 =  212
    12 * 12 =  111
    12 * 20 =  210
    12 * 21 =  222
    12 * 22 =  201
    20 * 20	=  100
    20 * 21 =  120
    20 * 22 =  110
    21 * 21 =  201
    21 * 22 =  102
    22 * 22 =  121
все остальные полиномы очевидно неприводимые
(смотри таблицу выше).

Теперь выберем примитивные полиномы из неприводимых:
неприводимые полиномы:
    --------------------
    101 	112    	122
    202     221	211
    ---------------------

неприводимый полином должен делить:
    X^[ p^n - 1] - 1
    X^[ 3^2 - 1] - 1
    X^[ 9 - 1] - 1
    X^8 - 1
    X^8 + 2
    100000002

но не должен делить X^d - 1, где d делит (p^N - 1) = 8
8 делят 4 и 2.

(2)	X^2 - 1  имеет степень меньше 3 и его никто естественно не делит
    101

(4)	X^4 - 1
    X^4 + 2
    10002

Рассмотрим наши полиномы:
[101]

    100000002
    101
        -----
      200
      202
          -----
        100
        101
            -----
          202
          202
              ---
                0

    10002
    101
        -----
      202		делит - поэтому не примитивный
      202
          ---
            0

[112]
    100000002
    112
        ----
     210
     221
          ---
      220
      221
          -----
        200
        221
             ---
         120
         112
             ----
          112
          112
          ---
            0

    10002
    112
        ----
     210
     221
     ---
      222		не делит - поэтому примитивный
      221
      ---
        1

[122]
    100000002
    122
        ----
     110
     122
         ----
      210
      211
          -----
        200
        211
            ----
         220
         211
             ---
          122
          122
          ---
        0

    10002
    122
    ---
     110
     122
         ---
      212
      211
      ---   не делит - значит примитивный
        1

И Соответсвенно для сопряженных:
(просто у нас троичный случай (в принципе он тоже вырожденный) и {2*P = -P}):
    202 = 2 * 101 - непримитивный
    211 = 2 * 122 - примитивный
    221 = 2 * 112 - примитивный

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


3.17.3. ПОЛЯ ГАЛУА GF[p,k]

Поля Галуа существуют не только для GF[p] = GF[p,1], где p - простое число.
Но также для GF[p,k], где p - простое число, а k - целое число.
Только в случаях k > 1 мы работаем не с числами, а с полиномами.
(случай k = 1 - в общем то тоже полином, но вырожденный:  1).

  GF[2^2]

GF[2^2] = GF[2,2] = GF[2, 2, X^2 + X + 1]

Элементы:   { 0,   1,  2,  3 }
        { 00, 01, 10, 11 }

Сложение:

        +  | 00 01 10 11
        ---+------------
        00 | 00 01 10 11
        01 | 01 00 11 10
        10 | 10 11 00 01
        11 | 11 10 01 00

Умножение:

примитивный полином: X^2 + X + 1   степени 2  [111]

    представляем:
        0		00
        1=X^0           01
        X		10
        X^2  непредставим в сетке.
             будем представлять по модулю образующего полинома:

        X^2              	100
        X^2 + X + 1             111
        -----------             ---
              X + 1   => 	 11

        ----------------------------------
        X^inf	0		0	-
        X^0	x^0 = 1         01      0
        X^1	x^1             10      1
        X^2	x^1 + 1         11      2
        -----------------------------------

Логарифмы:	{ inf, 0, 1, 2 }

Тогда умножение в виде степеней
        *  |  0 1 2 3
        ---+----------
         0 |  - - - -
         1 |  - 0 1 2
         2 |  - 1 2 0
             3 |  - 2 0 1

    реальная таблица умножения:

        *  | 1 2 3
        ---+--------
        1  | 1 2 3
        2  | 2 3 1
        3  | 3 1 2

  GF[2^3]

GF[2^3] = GF[2,3] = GF[2, 3, X^3 + X + 1]

Рассмотрим поле:
GF[8] = GF[2^3] = GF[2,3] = GF[2,3,X^2+X+1]

    F(X) = u2 * x^2 + u1 * x + u0
    где
        u2,u1,u0 - элементы алгебраической системы S

Сложение:
по правилам для полиномов в классе вычетов 2:

     + | 000 001 010 011 100 101 110 111
    ---+--------------------------------
    000| 000 001 010 011 100 101 110 111
    001| 001 000 011 010 101 100 111 110
    010| 010 011 000 001 110 111 100 101
    011| 011 010 001 000 111 110 101 100
    100| 100 101 110 111 000 001 010 011
    101| 101 100 111 110 001 000 011 010
    110| 110 111 100 101 010 011 000 001
    111| 111 110 101 100 011 010 001 000

    2+2 = 010 XOR 010 = 000	= 0 SUPER

а теперь в виде чисел:

     + | 0 1 2 3 4 5 6 7
     --+-----------------
     0 | 0 1 2 3 4 5 6 7
     1 | 1 0 3 2 5 4 7 6
     2 | 2 3 0 1 6 7 4 5
     3 | 3 2 1 0 7 6 5 4
     4 | 4 5 6 7 0 1 2 3
     5 | 5 4 7 6 1 0 3 2
     6 | 6 7 4 5 2 3 0 1
     7 | 7 6 5 4 3 2 1 0

Умножение:
Что бы обеспечить умножение полиномов надо выбрать примитивный полином
соотвествующей степени. для нашего случая подходит X^3+X+1 [1011]

0	000		0		000
x^0	001		x^0 = 1		001
x^1	010		x		010
x^2	100		x^2		100

x^3	непредставим - берем по модулю примитивного полинома x^3 + X +1

        x^3                 		1000
    [1]	x^3 + 0*X^2 + X + 1             1011
        ------------------------------------
                  X + 1              011

x^4	непредставим - берем по модулю

        x^4                             10000
    [x]	x^4 + 0*x^3 + X^2 + X		1011-
                        -----
                          110

x^5     непредставим - берем по модулю
        x^5                               100000
    [x^2]	x^5 + 0*x^4 + X^3 + X^2		  1011--
             ------------------------          ------
                  x^3 + X^2             1100
    [1]		      x^3 + 0   + X + 1     1011
                                                ----
                                                 111
x^6	непредставим - берем по модулю
        x^6                		    1000000
    [x^3]	x^6 + 0 + X^4 + X^3                 1011---
           -----------------------              -------
              x^4 + X^3         	      11000
    [x]		  x^4 + 0  + x^2 + X          1011-
           -------------------------------       ------
                x^3+x^2+X	       1110
                X^3+0  +X + 1	       1011
                   ---------------      -------
                   x^2 + 1              101

    ----------------------------------------
    power	polynom		vector	regular
    ----------------------------------------
    0	0		000	0
    x^0=1	1               001	1
    x^1	x		010	2
    x^2	x^2		100	4
    x^3	1+x		011	3
    x^4	x+x^2		110	6
    x^5	1+x+x^2		111	7
    x^6	1+x^2		101	5
    ----------------------------------------

    Соответственно степени
        ------------------------------------
        Число	log
        ------------------------------------
        1       0	7       -7      -14
        2       1       8       -6      -13
        4       2       9       -5      -12
        3       3       10      -4      -11
        6       4       11      -3      -10
        7       5       12      -2      -9
        5       6       13	-1	-8
        ------------------------------------

таблица умножения в виде степеней
         N| 1 2 3 4 5 6 7
        --+---------------
     N	power | 0 1 3 2 6 4 5
     ---------+---------------
     1 | 0| 0 1 3 2 6 4 5
     2 | 1| 1 2 4 3 0 5 6
     3 | 3| 3 4 6 5 2 0 1
     4 | 2| 2 3 5 4 1 6 0
     5 | 6| 6 0 2 1 5 3 4
     6 | 4| 4 5 0 6 3 1 2
     7 | 5| 5 6 1 0 4 2 3

а теперь в таблицу умножения

        * | 1 2 3 4 5 6 7
       ---+---------------
        1 | 1 2 3 4 5 6 7
        2 | 2 4 6 3 1 7 5
        3 | 3 6 5 7 4 1 2
        4 |	4 3 7 6 2 5 1
        5 | 5 1 4 2 7 3 6
            6 | 6 7 1 5 3 2 4
            7 | 7 5 2 1 6 4 3

    2*2 = k^1 * k^1 = 4  (не всегда бывает так)
    2*2 = k^(0-6) * k^(-6) = k(-12) = 4

Обратные элементы:
    1 * 1 = 1
        2 * 5 = 1
        3 * 6 = 1
        4 * 7 = 1
    5 * 2 = 1
    6 * 3 = 1
    7 * 4 = 1

Индекс - показатель степени при X (по модулю примитивного полинома)
которое дает данный полином

  GF[2^4]

  GF[3^2]

Рассмотрим теперь группу GF[3,2]:
GF[3^2] = GF[3,2] = GF[3,2, X^2 + 2X + 2]

сложение (обычное полиномальное по молулю 3):

       + | 00 01 02 10 11 12 20 21 22
      ---+----------------------------
       00| 00 01 02 10 11 12 20 21 22
       01| 01 02 00 11 12 10 21 22 20
       02| 02 00 01 12 10 11 22 20 21
       10| 10 11 12 20 21 22 00 01 02
       11| 11 12 10 21 22 20 01 02 00
       12| 12 10 11 22 20 21 02 00 01
       20| 20 21 22 00 01 02 10 11 12
       21| 21 22 20 01 02 00 11 12 10
       22| 22 20 21 02 00 01 12 10 11

теперь переведем это в числа:

    +| 0 1 2 3 4 5 6 7 8
       --+--------------------
    0| 0 1 2 3 4 5 6 7 8
    1| 1 2 0 4 5 3 7 8 6
    2| 2 0 1 5 3 4 8 6 7
    3| 3 4 5 6 7 8 0 1 2
    4| 4 5 3 7 8 6 1 2 0
    5| 5 3 4 8 6 7 2 0 1
    6| 6 7 8 0 1 2 3 4 5
    7| 7 8 6 1 2 0 4 5 3
    8| 6 7 6 2 0 1 5 3 4

Таблица умножения:

примитивный полином: X^2 + 2X + 2  [122]

Строим таблицу:

    0	00
    x^0=1	01
    x^1	10

    x^2	11
    ------------
    100
    122
    ---
     11

    x^3 	21
    ------------
    1000
    122
     110
     122
     ---
      21

    x^4  	02
    -----------
    10000
    122
     110
     122
      210	<-- обратите внимания все вычисления повторяются
      211
      ---
       02

    x^5   	20
    ----------
    020

    x^6	22
    ----------
    200
    211
    ---
     22

    x^7	12
    ----------
    220
    211
    ---
     12

    x^8	01	закончили
    120
    122
    ----
      1

    получаем:

    ---------------------------
    Число	Степень от 10
    ---------------------------
    00	infinity
(1)	01	0	8       -8
(3)	10	1       9       -7
(4)	11	2       10      -6
(7)	21	3       11      -5
(2)	02	4       12      -4
(6)	20	5       13      -3
(8)	22	6       14      -2
(5)	12	7       15	-1
    ---------------------------

таблица умножения в виде степеней:

    pow | 0 4 1 2 7 5 3 6
    ----+-----------------
     0  | 0 4 1 2 7 5 3 6
     4  | 4 0 5 6 3 1 7 2
         1  | 1 5 2 3 0 6 4 7
         2  | 2 6 3 4 1 7 5 0
         7  | 7 3 0 1 6 4 2 5
         5  | 5 1 6 7 4 2 0 3
         3  | 3 7 4 5 2 0 6 1
         6  | 6 2 7 0 5 3 1 4

таблица умножения в виде чисел:
      * | 1 2 3 4 5 6 7 8
      --+-----------------
      1 | 1 2 3 4 5 6 7 8
      2 | 2 1 6 8 7 3 5 4
      3 | 3 6 4 7 1 8 2 5
      4 | 4 8 7 2 3 5 6 1
      5 | 5 7 1 3 8 2 4 6
      6 | 6 3 8 5 2 4 1 7
      7 | 7 5 2 6 4 1 8 3
      8 | 8 4 5 1 6 7 3 2

    2*2 = 1 SUPER

Обратные элементы:
    1 * 1 = 1
    2 * 2 = 1  <- обратите особое внимание
    3 * 5 = 1
    4 * 8 = 1
    5 * 3 = 1
    6 * 7 = 1
    7 * 6 = 1
    8 * 4 = 1

Кроме того модно просто умножать по модулю примитивного полинома
например
    22	X^6
     *  20      X^5
    -----------------
       110	результат обычного умножения полиномов
       122	берем по модулю примитивного полинома
       ---
        21	X^11	все правильно


3.18. СМЕШАННЫЕ ОСТАТОЧНЫЕ КОЛЬЦА (RNS)

RNS (Residue Number System)

Берем набор простых чисел a1,...,aN.
(в принципе можно просто набор взаимно простых чисел)
(для повышения эффективности удобнее брать числа вида 2^k и 2^(k-1) )
С помощью этого набора мы можен представить все числа от 0 до a1*...*aN-1
Записывая числа как набор остатков от деления по модулю a{i}

Например возмем простые числа: 	{2,3,5}
RNS(2|3|5)

    C помощью этого набора мы сможен представить числа от 0 до
    2*3*5 = 30

    -------------------
    0	{0,0,0}
    1	{1,1,1}
    2	{0,2,2}
    3	{1,0,3}
    4	{0,1,4}
    5	{1,2,0}
    6	{0,0,1}
    7	{1,1,2}
    8	{0,2,3}
    9	{1,0,4}
    10	{0,1,0}
    11	{1,2,1}
    12	{0,0,2}
    13	{1,1,3}
    14	{0,2,4}
    15	{1,0,0}
    16	{0,1,1}
    17	{1,2,2}
    18	{0,0,3}
    19	{1,1,4}
    20	{0,2,0}
    21	{1,0,1}
    22	{0,1,2}
    23	{1,2,3}
    24	{0,0,4}
    25	{1,1,0}
    26	{0,2,1}
    27	{1,0,2}
    28	{0,1,3}
    29	{1,2,4}
    -------------------

    -------------------
    0	{0,0,0}
    6	{0,0,1}
    12	{0,0,2}
    18	{0,0,3}
    24	{0,0,4}
    10	{0,1,0}
    16	{0,1,1}
    22	{0,1,2}
    28	{0,1,3}
    4	{0,1,4}
    20	{0,2,0}
    26	{0,2,1}
    2	{0,2,2}
    8	{0,2,3}
    14	{0,2,4}
    15	{1,0,0}
    21	{1,0,1}
    27	{1,0,2}
    3	{1,0,3}
    9	{1,0,4}
    25	{1,1,0}
    1	{1,1,1}
    7	{1,1,2}
    13	{1,1,3}
    19	{1,1,4}
    5	{1,2,0}
    11	{1,2,1}
    17	{1,2,2}
    23	{1,2,3}
    29	{1,2,4}
    -------------------

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

Например:
    12+15
        12	{0,0,2}
        15	{1,0,0}
        ----------------
        12+15  	{1,0,2}	 = 27

    3*7
        3	{1,0,3}
        7	{1,1,2}
        ----------------
        3*7	{1,0,1}	  = 21

    Существование обратного элемента по сложению
    13	{1,1,3}
    -13	{2-1,3-1,5-3} = {1,2,2}

        13	{1,2,2}
       +	-13	{1,1,3}
        -----------------
        0	{0,0,0}

Нахождение обратных элементов по умножению труднее.
Понятно что есть единица {1,1,1}

Для каждого разряда можно найти свои обратные элементы по умножению.
RSN(2|3|5)

    2:
       * | 0  1
      ---+-------
       0 | 0  0
       1 | 0  1

    3:
       * | 0  1  2
      ---+---------
       0 | 0  0  0
       1 | 0  1  2
       2 | 0  2  1

    5:
       * | 0  1  2  3  4
      ---+----------------
       0 | 0  0  0  0  0
       1 | 0  1  2  3  4
       2 | 0  2  4  1  3
       3 | 0  3  1  4  2
       4 | 0  4  3  2  1

    Xi / Mi = Xi * (1/Mi) mod P

Пример:
    28/7 = {0,1,3}  / {1,1,2}

        2: 0/1 = 0
        3: 1/1 = 1
        5: 3/2 = 4	(3*4 = 2)
    {0,1,4} =  4

    28/27 = {0,1,3} / {1,0,2}
        2: 0/1 = 0
        3: 1/0 = ?	Вот она проблема с делителями нуля
        5: 3/2 = 4
    типа не делиться - нет такого числа
    а что же вы хотели у нас же не поле, а кольцо.

Но в нашем кольце очень много делителей нуля (больше двух третей кольца):
Это числа вида:
    { *, *, 0 }
    { *, 0, * }
    { 0, *, * }

Пример:
        {1,2,0}
        *	{0,0,2}
       ------------
        {0,0,0}

Конвертация из обычного формата
    22 -> RNS(2|3|5)

    22 mod 2 = 0
    22 mod 3 = 1
    22 mod 5 = 2

    {0,1,2} 22

Это можно упростить для бинарного случая например (да и для любого)
используя таблицы  P^j mod M, где p - основание СЧ из которой переводить,
M - каждый из RNS баз.

Например  для RNS(7|5|3)

    ----------------------------------------------------------
    j	2^j	(2^j)mod7	(2^j)mod5	(2^j)mod3
    ----------------------------------------------------------
    0	1	1		1		1
    1	2	2		2		2
    2	4	4		4		1
    3	8	1		3		2
    4	16	2		1		1
    5	32	4		2		2
    6	64	1		4		1
    7	128	2		3		2
    8	256	4		1		1
    9	512	1		2		2
    ----------------------------------------------------------

Соответсвенно:
    11011 -> RSN(7|5|3):

    ------------------------------------------------------------
            current	  sum	current	sum 	current	sum
    Xi*2^i		7         7        5     5        3      3
    -----------------------------------------------------------
            -	  0        -     0        -      0
    1*2^0		1	  1	   1     1        1      1
    1*2^1	        2         3        2     3        2      0
    0*2^2		0	  3	   0     3	  0      0
    1*2^3		1         4        3     1        2      2
    1*2^4		2         6        1     2        1      0
    ------------------------------------------------------------

Значит 11011{2} = (6,2,0){RSN(7|5|3)}

Конвертация обратно:
   RNS(2|3|5)

        {0,0,1}	6	multiple of 6  (2*3) which is 1 mod 5 = 6
    {0,1,0} 10	multiple of 10 (2*5) which is 1 mod 3 = 10
    {1,0,0} 15	multiple of 15 (3*5) which is 1 mod 2 = 15

23	{1,2,3}  =  1 * {1,0,0}
                 +  2 * {0,1,0}
                 +  3 * {0,0,1}

         =  1* 15 + 2*10 + 3*6 = 15 + 20 + 18 =
         =  53 mod (2*3*5) =  53 mod 30 = 23.

так что конвертация обратно в нормальный формат делается без особых проблем.

Представление отрицательных чисел в RSN:

    -X  = M - X, где N - произведение всех чисел в базе RNS

Например для RNS(2|3|5)

    0	{0,0,0}
       -0	{2-0,3-0,5-0} = {0,0,0} специальный случай

    1	{1,1,1}
       -1	{2-1,3-1,5-1} = {1,2,4}	 29
    2	{0,2,2}
       -2	{2-0,3-2,5-2}   = {0,1,3}  28
    итд

    15	{1,0,0}
       -15	{2-1,0,0} = {1,0,0} 15  типа специальный случай

    -------------------
    0	{0,0,0}
    1	{1,1,1}
    2	{0,2,2}
    3	{1,0,3}
    4	{0,1,4}
    5	{1,2,0}
    6	{0,0,1}
    7	{1,1,2}
    8	{0,2,3}
    9	{1,0,4}
    10	{0,1,0}
    11	{1,2,1}
    12	{0,0,2}
    13	{1,1,3}
    14	{0,2,4}
    15	{1,0,0}
    -14	{0,1,1}
    -13	{1,2,2}
    -12	{0,0,3}
    -11	{1,1,4}
    -10	{0,2,0}
    -9	{1,0,1}
    -8	{0,1,2}
    -7	{1,2,3}
    -6	{0,0,4}
    -5	{1,1,0}
    -4	{0,2,1}
    -3	{1,0,2}
    -2	{0,1,3}
    -1	{1,2,4}
    -------------------

Что трудно в RNS?

    Узнать какое число положительное, какое отрицательное
    Узнать произошло ли у нас переполнение во время операции
    Сравнивать числа (трудно вычислить модуль)


3.19. ДРОБНЫЕ СИСТЕМЫ СЧИСЛЕНИЯ

Возьмем число p - основание системы счисления 1 < p < 2
Цифры: {0, 1}

Для положительного целого числа A находим наибольшее n1 такое что

    p^n1 <= A

Затем применяем эту процедуру к (A - p^n1)
итд

Собственно мы представляем целые числа в системе с дробным основанием
методом приближения к низу.

В принципе чем ближе p к единице тем тем больше подряд нулей между соседними
единицами т.к. неравенство  p^n1 + p^n2 < p^(n1+1) должно естественно выполняться.

Удобнее всего брать основание для которого выполняется соотношение a^2 = a + 1
(но это уже получаем Систему Бергмана).

Рассмотрим СЧ с основанием равным 3/2 = 1.5

Цифры: {0, 1}

Базис:
    --------------------------
    7	17.0859375
    6	11.390625
    5	7.59375
    4	5.0625
    3	3.375
    2	2.25
    1	1.5
    0	1
    --------------------------

Числа:
    ---------------------------
    0	0
    1	1
    2	10
    3	100
    4	1000
    5	1100
    6	10000
    7	10010
    8	100000
    9	100001
    10	100010
    11	101000
    12	1000000
    13	1000010
    14	1000100
    15	1001000
    16	1001001
    17	1010000
    18	10000000
    ---------------------------

Понятно что Арифметические операции сложные и приближенные.

А теперь рассмотрим СЧ с основанием 1.9

Цифры: {0, 1}

Базис:
    --------------------------
    5	24.76099
    4	13.0321
    3	6.859
    2	3.61
    1	1.9
    0	0
    --------------------------

Числа:
    ---------------------------
    0	0
    1	1
    2	10
    3	11
    4	100
    5	101
    6	110
    7	1000
    8	1001
    9	1010
    10	1011
    11	1100
    12	1101
    13	1110
    14	10000
    15	10010
    16	10011
    17	10100
    18	10101
    19	10110
    20	11000
    21	11001
    22	11010
    23	11011
    24	11100
    25	100000
    ---------------------------

Добавим избыточность в систему с основнием 1.5
Это позволит нам точно представить все целые числа.

Цифры: {0, 1, 2}

Базис:
    --------------------------
    7	17.0859375
    6	11.390625
    5	7.59375
    4	5.0625
    3	3.375
    2	2.25
    1	1.5
    0	1
    --------------------------

Числа:
    ---------------------------
    0	0
    1	1
    2	2
    10	1.5
    11	2.5
    12	3.5
    20	3
    21	4
    22	5
    100	2.25
    101	3.25
    102	4.25
    110	3.75
    111	4.75
    112	5.75
    120	5.25
    121	6.25
    122	7.25
    200	4.5
    201	5.5
    202	6.5
    210	6
    211	7
    212	8
    220	7.5
    221	8.5
    222	9.5
    ---------------------------

По крайней мере мы сможем совместить соседние домены:

Таблица сложения:
    ----------------
    +  |  0   1   2
    ---+------------
    0  |  0   1   2
    1  |  1   2  20
    2  |  2  20  21
    ----------------

    Например: 8 = 212
          9 = 212 + 1

    212 + 001 = 210 + 020 = 200 + 200 = 200 + 100 + 100 = 2000 + 100 = 2100

    Проверка:
        2100 = 2*3.375 + 1*2.25 = 6.75 + 2.25 = 9	все верно

Таблица умножения:
    ----------------
    *  |  0   1   2
    ---+------------
    0  |  0   0   0
    1  |  0   1   2
    2  |  0   2  21
    ----------------

    Пример:
        2 * 4
        2 = 2
        4 = 21

        21
       *	 2
          -----
         2
           21
          -----
           212  = 8

Чтобы можно было хранить все целые числа необходимо чтобы домены пересекались.
Для этого надо так подбирать цифры - что бы они помогали связывать домен.
Таким образом для для получения целой части в старшем разряде нужна цифра:

    ----------------------------------------------------------------------
    1.5  	1+1/2	2	2*(1+1/2) = 3
    1.(3)	1+1/3	3	3*(1+1/3) = 4
    1.25	1+1/4	4	4*(1+1/4) = 5
    ----------------------------------------------------------------------
    1.(6)	1+2/3	3 (?)	3*(1+2/3) = 5   - а где хранить 4? - значит 4
    1.(6)	1+2/3	4 (!)	3*(1+2/3) = 5	- цифры 0..4
    ----------------------------------------------------------------------
    1.75	1+3/4	4 (?)	4*(1+3/4) = 7   - а где хранить 5 и 6? - значит 6
    1.75	1+3/4	6 (!)	4*(1+3/4) = 7   - цифры  0..7
    ----------------------------------------------------------------------
    1.3	1+3/10	A (?)	10*(1+3/10) = 13 - надо еще 11 и 12
    1.3	1+3/10	C (!)	10*(1+3/10) = 13 - цифры 0..C
    ----------------------------------------------------------------------
    1.9	1+9/10	A (?)	10*(1+9/10) = 19 - а надо 11..18
    1.9	1+9/10	I (?)	10*(1+9/10) = 19 - цифры  0..I (0..18)
    ----------------------------------------------------------------------


3.20. ПРИЗНАКИ ДЕЛИМОСТИ

  Отношения сравнения

Если  a = b (mod n)
и     с = d (mod n), то

a + c = b + d (mod n)
a * c = b * d (mod n)

  Признак Паскаля

Признак Паскаля
основание системы счистления = n
число для которого вычисляется признак делимости = m

тогда:
    r1 = n mod m
    r2 = n * r1  mod m
    r3 = n * r2  mod m
    ....
    r{i} = n * r{i-1} mod m

так как остатков конечное число то рано или поздно
процесс закончиться.

Число

A =  n^i * a{i} + ... + n^2 * a{2} + n * a{1} + a{0}

имеет тот же остаток от деления что и

     r{i} * a{i} + ... + r2 * a{2} + r1 * a{1} + a{0}

общии признаки:
    n^i mod (n-1) = 1
    n^i mod (n+1) = (-1)^i

 --------------------------------------------------------------------
    делитель       	делитель       	делитель
n	n       n-1     n-1    	n+1	n+1
 --------------------------------------------------------------------
2	-	-	-	3	-
3	-	2	-	4	2
4	2	3	-	5	-
5	-	4	2	6	2,3
6	2,3	5	-	7	-
7	-	6	2,3	8	2,4
8	4,2	7	-	9	3
9	3	8	2,4	10	2,5
10	2,5	9	3	11	-
11	-	10	2,5	12	2,3,4
12	2,3,4	11	-	13	-
13	-	12	2,3,4	14	2,7
14	2,7	13	-	15	3,5
15	3,5	14	2,7	16	2,4,8
16	2,4,8	15	3,5	17	-
 --------------------------------------------------------------------

на n-1:
    r0 = 1
    r1 = n mod n-1 =  1
    сумма цифр числа
    тоже самое для его делителей (если есть)

на n+1:	r0 = 1
    r1 = n mod n+1 = -1
    r2 = -n mod n+1 = 1
    чередование

Признаки делимости можно использовать для быстрого получения остатков от деления.
Особенно важно вычисление остатков от деления для перевода в RNS.

  10

Признаки делимости в десятичной системе счисления:

на 2:	число четно
на 3:   сумма цифр числа делиться на 3
на 4:   число образованное последними двумя цифрами исходного
        числа делиться на 4
на 5:   последняя цифра числа: 0 или 5
на 6:   делиться на 2 и 3
на 7:   число без последней цифры минус удвоенная последняя
        цифра делиться на 7.
    371: 37 - 2 * 1 = 35 : 3 - 5 * 2 = -7
на 8:   число образованное последними тремя цифрами исходного
        числа делиться на 8
на 9:   сумма цифр числа делиться на 9
на 10:  последняя цифра числа: 0
на 11:  сумма цифр числа с чередующимися знаками делиться на 11
    182919:  + 1 - 8 + 2 - 9 + 1 - 9 = -22
на 12:  делиться на 3 и 4
на 13:  число десятков + учетверенное число единиц кратно 13
    845:  84 + 4 * 5 = 104:  10 + 4 * 4 = 26
на 14:  делиться на 2 и 7
на 15:  делиться на 3 и 5

Для десятичной системы:

на 2:	r0 = 1
    r1 = 10 mod 2 = 0
    1 цифра

на 3:	r0 = 1
    r1 = 10 mod 3 = 1
    сумма цифр

на 4:	r0 = 1
    r1 = 10 mod 4 = 2
    r2 = 20 mod 4 = 0
    2 цифры

на 5:	r0 = 1
    r1 = 10 mod 5 = 0
    1 цифра

на 6:	r0 = 1
    r1 = 10 mod 6 = 4
    r2 = 40 mod 6 = 4
    составное

на 7:	r0 = 1
    r1 = 10 mod 7 = 3
    r2 = 30 mod 7 = 2
    r3 = 20 mod 7 = 6	// -1
    r4 = 60 mod 7 = 4	// -3
    r5 = 40 mod 7 = 5  *	// -2
    r6 = 50 mod 7 = 1  *

на 8:	r0 = 1
    r1 = 10 mod 8 = 2
    r2 = 20 mod 8 = 4
    r3 = 40 mod 8 = 0
    3 цифры

на 9:	r0 = 1
    r1 = 10 mod 9 = 1
    сумма цифр

на 10:	r0 = 1
    r1 = 10 mod 10 = 0
    1 цифра

на 11:	r0 = 1
    r1 = 10 mod 11 = -1
    ....
    чередование со знаками

на 12:	r0 = 1
    r1 = 10 mod 12 = 10
    r2 = 100 mod 12 = 4
    r3 = 40 mod 12 = 4
    составное

на 13:	r0 = 1
    r1 = 10 mod 13 = 10
    r2 = 100 mod 13 = 9
    r3 = 90 mod 13 = 12
    r4 = 120 mod 13 = 3
    r5 = 30 mod 13 = 4   *
    r6 = 40 mod 13 = 1   *

на 14:  r0 = 1
    r1 = 10 mod 14 = 10
    r2 = 100 mod 14 = 2
    r3 = 20 mod 14 = 6
    r4 = 60 mod 14 = 4
    r5 = 40 mod 14 = 12	//-2
    r6 = 120 mod 14 = 8  	//-6
    r7 = 80 mod 14 = 10	//-4

на 16:	r0 = 1
    r1 = 10 mod 16 = 10
    r2 = 100 mod 16 = 4
    r3 = 40 mod 16 = 8
    r4 = 80 mod 16 = 0
    4 цифры

на 17:	r0 = 1
    r1 = 10 mod 17 = 10
    r2 = 100 mod 17 = 15
    r3 = 150 mod 17 = 14
    r4 = 140 mod 17 = 4
    r5 = 40 mod 17 = 6
    r6 = 60 mod 17 = 9
    r7 = 90 mod 17 = 5
    r8 = 50 mod 17 = 16
    r9 = 160 mod 17 = 7
    r10 = 70 mod 17 = 2
    r11 = 20 mod 17 = 3
    r12 = 30 mod 17 = 13
    r13 = 130 mod 17 = 11
    r14 = 110 mod 17 = 8
    r15 = 80 mod 17 = 12    *
    r16 = 120 mod 17 = 1	*

Таблица умножения

    11	12	13	14	15	16	17	18	19	20	21
2	22	24	26	28	30	32	34	36	38	40	42
3	33	36	39	42	45	48	51	54	57	60	63
4	44	48	52	56	60	64	68	72	76	80	84
5	55	60	65	70	75	80	85	90	95	100	105
6	66	72	78	84	90	96	102	108	114	120	126
7	77	84	91	98	105	112	119	126	133	140	147
8	88	96	104	112	120	128	136	144	152	160	168
9	99	108	117	126	135	144	153	162	171	180	189
10	110	120	130	140	150	160	170	180	190	200	210
11	121	132	143	154	165	176	187	198	209	220	231
12	132	144	156	168	180	192	204	216	228	240	252
13	143	156	169	182	195	208	221	234	247	260	273
14	154	168	182	196	210	224	238	252	266	280	294
15	165	180	195	210	225	240	255	270	285	300	315
16	176	192	208	224	240	256	272	288	304	320	336
17	187	204	221	238	255	272	289	306	323	340	357
18	198	216	234	252	270	288	306	324	342	360	378
19	209	228	247	266	285	304	323	342	361	380	399
20										400	420

  3

Троичная система:
на 2:   сумма цифр делиться на 2
на 3:   последняя цифра 0
на 4:   чередование
    r0 = 1
    r1 = 3 mod 4 = 3	// -1
    r2 = 3*3 mod 4 = 1

на 5:	r0 = 1
    r1 = 3 mod 5 = 3	// -2
    r2 = 3*3 mod 5 = 4	// -1
    r3 = 3*4 mod 5 = 2   *
    r4 = 3*2 mod 5 = 1   *

  16

Шестнадцитеричная система:

на 2:	четное
на 3:	сумма цифр делиться на 3
на 5:	сумма цифр делиться на 5
на 6:   делиться на 2 и 3
на 8:   последняя цифра 0 или 8
на A:   четное + сумма цифр делиться на 5
на F:	сумма цифр делиться на F

на 7:	r0 = 1
    r1 = 16 mod 7 = 2
    r2 = 16*2 mod 7 = 32 mod 7 = 4
    r3 = 16*4 mod 7 = 64 mod 7 = 1

на 9:	r0 = 1
    r1 = 16 mod 9 = 7
    r2 = 16*7 mod 9 = 112 mod 9 = 22 mod 9 = 4
    r3 = 16*4 mod 9 = 64 mod 9 = 1


3.21. СИСТЕМЫ СЧИСТЛЕНИЯ С ДВОЙНЫМ ОСНОВАНИЕМ

THIS SECTION IS UNDER CONSTRUCTION

DBNS (Double Base Numeric System)

Берем два простых числа p,q, числа представляются в виде

    N = SUM{i=1..l} S{i}P^(Ai)Q^(Bi)

S{i} = 1, 0, -1.

P и Q как правило берут 2 и 3. так наиболее выгодно (см 3.11 ОПТИМАЛЬНАЯ СИСТЕМА
СЧИСТЛЕНИЯ).
И часто берут цифры только 0 и 1. (то есть -1 не используют)

Основное преймущество - малое число единичных разрядов в представлении
Удобно использовать для хранения больших LUT (Lookup Table), так как затраты
на конвертер малы по сравнению с затратами на храненение.

  DBNS{2,3}

1 =  1 {0,0}

2 =  2 {1,0}

3 =  2 {1, 0} + 1 {0,0}
3 =  3 {0, 1}

4 =  4 {2, 0}
4 =  3 {0, 1} +  1 {0, 0}

5 =  4 {2, 0} + 1 {0, 0}
5 =  3 {0, 1} + 2 {1, 0}

6 =  3*2 {1,1}
6 =  4 {2, 0} + 2 {1, 0}
6 =  3 {0, 1} + 2 {1, 0} + 1 {0,0}

7 = 6 + 1
7 = 3 + 4
7 = 4 + 2 + 1

8 = 6 + 2
8 = 3 + 4 + 1
8 = 8

9 = 9
9 = 6 + 3
9 = 6 + 2 + 1
9 = 3 + 4 + 2
9 = 8 + 1

10 = 9 + 1
10 = 6 + 3 + 1
10 = 6 + 4
10 = 3 + 4 + 2 + 1
10 = 8 + 2

11 = 9 + 2
11 = 6 + 3 + 2
11 = 6 + 4 + 1
11 = 3 + 8
11 = 8 + 2 + 1

DBNR (Double Bases Number Representation) - минимальное предствление числа в DBNS

X 	Минимальное число единичек чтобы представить X в {2,3}
1		1
5		2
23		3
431		4
18431		5
3448733		6
1441896119	7

Избыточность:

    10    имеет  5      представлений
    100   имеет 42      представления
    1000  имеет 1295579 представлений

Минимальное представление требует порядка (n/log(n)) {p,q} разрядов


4. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ

Логические функции которые мы рассматривали в 3. имеют обозначения в
виде логических элементов:

существует 2 типа схемотехнических обозначений

  •  американская (ANSI)

  •  европейская  (DIN)

  NOT

ANSI/DIN

           -----------
        X | NOT X
               ---+-------
        0 | 1
            1 | 0
           -----------

  AND

ANSI

DIN

        AND |  0  1  	карта Карно
                ----+--------+
                  0 |  0  0  |
                  1 |  0  1  |
                    +--------+

               ---------------
        X1  X2  | AND	таблица истинности
           ---------+-----
        0   0   | 0
        0   1   | 0
            1   0   | 0
        1   1   | 1
               ---------------

ANSI

DIN

трехвходовое AND

                ----------------
         X1 X2 X3 | AND
        ----------+-----
         0  0  0  | 0
         0  0  1  | 0
         0  1  0  | 0
         0  1  1  | 0
         1  0  0  | 0
         1  0  1  | 0
         1  1  0  | 0
         1  1  1  | 1
                ----------------

  OR

ANSI

DIN

        OR |  0  1
    ---+--------+
         0 |  0  1  |
         1 |  1  1  |
           +--------+

        --------------
    X1  X2	| OR
    --------+-----
    0   0	| 0
    0   1	| 1
    1   0	| 1
    1   1	| 1
        --------------

ANSI

DIN

трехвходовое OR

                ----------------
         X1 X2 X3 | OR
        ----------+-----
         0  0  0  | 0
         0  0  1  | 1
         0  1  0  | 1
         0  1  1  | 1
         1  0  0  | 1
         1  0  1  | 1
         1  1  0  | 1
         1  1  1  | 1
                ----------------

  NOR

ANSI

DIN

      NOR | 0  1
         ----+------+
       0 | 1  0 |
       1 | 0  0 |
             +------+

ANSI

DIN

трехвходовое NOR

        ----------------
         X1 X2 X3 | NOR
        ----------+-----
         0  0  0  | 1
         0  0  1  | 0
         0  1  0  | 0
         0  1  1  | 0
         1  0  0  | 0
         1  0  1  | 0
         1  1  0  | 0
         1  1  1  | 0
        ----------------

  NAND

ANSI

DIN

    NAND | 0  1
    -----+------+
       0 | 1  1 |
       1 | 1  0 |
             +------+

трехвходовое NAND

        -----------------
         X1 X2 X3 | NAND
        ----------+------
         0  0  0  | 1
         0  0  1  | 1
         0  1  0  | 1
         0  1  1  | 1
         1  0  0  | 1
         1  0  1  | 1
         1  1  0  | 1
         1  1  1  | 0
        -----------------

  XOR

ANSI

DIN

    XOR  | 0  1
    -----+------+
       0 | 0  1 |
       1 | 1  0 |
         +------+

трехвходовое XOR

        ----------------
         X1 X2 X3 | XOR
        ----------+-----
         0  0  0  | 0
         0  0  1  | 1
         0  1  0  | 1
         0  1  1  | 0
         1  0  0  | 1
         1  0  1  | 0
         1  1  0  | 0
         1  1  1  | 1
        ----------------

  XNOR

XNOR - это XOR-NOT, т.е. EQV

    XNOR  |  0  1
    ------+--------+
        0 |  1  0  |
        1 |  0  1  |
          +--------+

трехвходовое XNOR

        -----------------
         X1 X2 X3 | XNOR
        ----------+------
         0  0  0  | 1
         0  0  1  | 0
         0  1  0  | 0
         0  1  1  | 1
         1  0  0  | 0
         1  0  1  | 1
         1  1  0  | 1
         1  1  1  | 0
        -----------------


4.1. ЭЛЕКТРИЧЕСКИЕ СИГНАЛЫ

Ток - движение носителей заряда (электронов)

Электроны обладают отрицательным зарядом и движуться от - к +.

Сила тока - количество заряда прошедшее за единицу времени

Постоянный и переменный ток

Alternating Current source (AC) Переменный ток
Direct Current source (DC) 	Постоянный ток

Может быть и такое: переменный ток имеющий постоянную составляющую.

Униполярный сигнал - только в одну сторону от 0 (GND)
Биполярный сигнал  - в обе стороны от 0


4.1.1. УРОВНИ СИГНАЛОВ

  Уровни сигналов:

1 соответствует +4.8V
0 соответствует +0.4V

V
+5V	+--------+
    |   1	 |
+3.5V	+--------+ граница зависит от технологии
    |	 |
    |	 | НЕОПРЕДЕЛЕННАЯ ЗОНА
    |        |
1.5V	+--------+ граница зависит от технологии
    |   0	 |
0V      +--------+

  Уровни сигналов детально

различным технологиям соответсвуют различные уровни сигнала:

       5V TTL			   5V CMOS

   Vcc	---  4.5-5.5    	Vcc  ---  4.5-5.5
     |                            |
         |                      Voh  ---  Vcc-0.2
     |			      |
     |                      Vih  ---  0.7*Vcc
     |			      |             --+
   Voh  ---  2.4                Vt   ---  2.5         |
         |                            |               | Неопределенная
   Vih  ---  2.0                      |               | зона
     |                            |               |
   Vt   ---  1.5                      |             --+
     |                            |
   Vil  ---  0.8                Vil  --- 0.3*Vcc
     |                            |
   Vol  ---  0.4                Vol  --- 0.5
     |                            |
   GND  ---  0                  GND  ---

Vcc - напряжение питания
Voh - (output high)  уровень 1 на выходе
Vih - (input  high)  уровень 1 на входе
Vt  - (toggle)	     уровень переключения
Vil - (input  low)   уровень 0 на входе
Vol - (output low)   уровень 0 на выходе
GND - (ground)	     земля

уровни сигналов CMOS:

уровни сигналов TTL:

    3.3V LVTTL  		  2.5V CMOS

   Vcc	---  3.0-3.6
     |
   Voh  ---  2.4                Vcc  ---  2.3-2.7
     |                            |
   Vih  ---  2.0                Voh  ---  Vcc-0.2
     |                            |
   Vt   ---  1.5                Vih  ---  0.7*Vcc
     |                            |
     |                      Vt   ---  1.25
     |                            |
   Vil  ---  0.6                Vil  ---  0.2*Vcc
     |                            |
   Vol  ---  0.4                Vol  ---  0.2
     |                            |
   GND  ---  0                  GND  ---  0

       GTL

   Vcc  ---  1.5
     |
   Voh  ---  1.2
         |
   Vih  ---  0.85
     |
   Vt   ---  0.8
     |
   Vil  ---  0.75
     |
   Vol  ---  0.4
     |
   GND  ---  0

       ECL

   GND  ---  0
     |
Vih/Voh	---  -0.810
     |
    Voh ---  -0.980
     |
    Vih ---  -1.105
     |
    Vil ---  -1.475
     |
    Vol ---  -1.630
     |
Vil/Vol ---  -1.850
     |
    Vcc ---   ~ -2.1

    PECL

   Vcc	---  5
     |
   Voh  ---  4.13
     |
   Vih	---  4.1
     |
   Vil	---  3.3
     |
   Vol	---  3.19
     |
  GND	---  0

TTL   - уровни сигналов (Transistor-Transistor Logic)
LVTTL - (Low voltage TTL)  TTL c низким напряжением
CMOS  - (Complimentary MOS)
ECL   - (Emmiter Connected Logic)
PECL  - (Positive ECL)
GTL   - (Gunning Transeiver Logic)

Электроны (знак заряда -) текут на (+) т.е. электроны движутся от GND к Vcc.

                 Vcc
        ---
         |
  течет	   |	 |     ^
  ток	   |	 |     | движутся электроны
       V 	 |     |
         |
        ---
        GND


4.1.2. КАК ЧИТАТЬ ВРЕМЕННЫЕ ДИАГРАММЫ

  Логика негативная и позитивная

Позитивная логика:
    состоянию логической  1 соответствует высокий уровень сигнала
    состоянию логического 0 соответствует низкий уровень сигнала

Негативная логика:
    все наоборот:
    состоянию логической  1 соответствует низкий уровень сигнала
    состоянию логического 0 соответствует высокий уровень сигнала

Например:
    RESET`	- сброс компьютера, когда сигнал высокий
    RESET#	- сброс компьютера, когда сигнал низкий

  Временные диаграммы

Временные диаграммы показывают уровень сигнала от времени.

High		Высокий уровень. (1)
        Соответствует активному для обычного сигналу
        Соответствует неактивному дла инверсного сигнала.
Low		Низкий уровень (0)
        Соответствует неактивному для обычного сигналу
        Соответствует активному дла инверсного сигнала.
Rising Edge	Фронт
        соответствует переходу от низкого уровня к высокому
Falling Edge	Спад
        соответствует переходу от высокого уровня к низкому


4.1.3. УРОВНИ СИГНАЛОВ В HDLs

  HDLs

Языки разработки электронной аппаратуры
(HDLs - Hardware Description Languages)

В этой секции мы расмотрим модели логических элементов на языках
разработки электронной аппаратуры:

  •  VHDL (VLSI Hardware Description Language)

  •  Verilog

Упор будет делатся на VHDL, т.к. он для начинающих более понятен.
Можно сравнить:
    VHDL	- Pascal
    Verilog	- C

Для моделирования схем цифровой электроники логики 1/0 недостаточно,
так как у нас могут быть шины, разные силы сигналов, высокоимпедансные выходы,
и.т.д, поэтому приходится ее расширять:

  VHDL

Уровни сигнала в VHDL:
std_logic:
    ------------------------------------
    U	не инициализирован
    X	неизвестен (high level)
    0	логический 0
    1	логическая 1
    Z	высокоимпедансное состояние
    W	неизвестен (low level)
    L	логический 0 (low level)
    H	логическая 1 (low level)
    -	неопределен (не важно)
    ------------------------------------

Ниже расписаны упрощеный вариант части пакета 1164 для VHDL,
который как раз занимается разрешением логики для соединений и
логических функций

type std_ulogic is (
        'U',		-- Uninitialized
        'X',		-- Forcing unknown
        '0',		-- Forcing 0
        '1',		-- Forcing 1
        'Z',		-- High impedance
        'W',		-- Weak unknown
        'L',		-- Weak 0
        'H',		-- Weak 1
        '-'		-- Don't care
        );

type std_ulogic_vector is array(natural range) of std_ulogic;

function resolved(s : std_ulogic_vector) return std_ulogic;

subtype std_logic is resolved std_ulogic;

type stdlogic_table is array(std_ulogic, std_ulogic) of std_ulogic;

CONTANT resolution_table : stdlogic_table :- (
--   U    X    0    1    Z    W    L    H    -
  ( 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U' ),  -- U
  ( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' ),  -- X
  ( 'U', 'X', '0', 'X', '0', '0', '0', '0', 'X' ),  -- 0

Здесь продолжает идти определение таблицы разрешений
но мы ее рассмотрим ниже потом.

  ( 'U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X' ),  -- H
  ( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' )   -- -
);

FUNCTION resolved(s: std_logic_vector) RETURN std_ulogic IS
VARIABLE result : std_ulogic := 'Z';
BEGIN
    if (s'length =  1) then return s(s'low);
    else
        for i in s'range loop
            result := resolution_table(result, s(i));
        end loop;
    end if;
    return	result;
end	resolved

Описания таблиц для and, not, or и xor мы тоже пропустим.

function "and" (l:std_ulogic, r:std_ulogic) return std_ulogic is
begin
    return	and_table(l,r);
end;

function "not" (l:std_ulogic) return std_ulogic is
begin
    return	(not_table(l));
end;

function "nand" (l:std_ulogic, r:std_ulogic) return std_ulogic is
begin
    return	not_table(and_table(l,r));
end;

Собственно это таблицы логических функций для VHDL std_logic:

Resolution table (то есть когда электрическое соединение)
  --------------------------
    U X 0 1 Z W L H -
  --------------------------
U	U U U U U U U U U
X	U X X X X X X X X
0 	U X 0 X 0 0 0 0 X
1       U X X 1 1 1 1 1 X
Z       U X 0 1 Z W L H X
W       U X 0 1 W W W W X
L       U X 0 1 L W L W X
H       U X 0 1 H W W H X
-       U X X X X X X X X
  --------------------------

and_table:
  --------------------------
    U X 0 1 Z W L H -
  --------------------------
U	U U 0 U U U 0 U U
X       U X 0 X X X 0 X X
0       0 0 0 0 0 0 0 0 0
1 	U X 0 1 X X 0 1 X
Z	U X 0 X X X 0 X X
W	U X 0 X X X 0 X X
L	0 0 0 0 0 0 0 0 0
H	U X 0 1 X X 0 1 X
-	U X - X X X 0 X X
  --------------------------

or_table:
  --------------------------
    U X 0 1 Z W L H -
  --------------------------
U	U U U 1 U U U 1 U
X       U X X 1 X X X 1 X
0	U X 0 1 X X 0 1 X
1	1 1 1 1 1 1 1 1 1
Z	U X X 1 X X X 1 X
W	U X X 1 X X X 1 X
L	U X 0 1 X X 0 1 X
H	1 1 1 1 1 1 1 1 1
-	U X X 1 X X X 1 X
  --------------------------

xor_table:
  --------------------------
    U X 0 1 Z W L H -
  --------------------------
U	U U U U U U U U U
X	U X X X X X X X X
0	U X 0 1 X X 0 1 X
1	U X 1 0 X X 1 0 X
Z	U X X X X X X X X
W	U X X X X X X X X
L	U X 0 1 X X 0 1 X
H	U X 1 0 X X 1 0 X
-	U X X X X X X X X
  --------------------------

not_table
  --------------------------
    U X 0 1 Z W L H -
  --------------------------
result	U X 1 0 X X 1 0 X
  --------------------------

  Verilog:

Уровни сигнала в Verilog
    ------------------------------------
    0	логический 0
    1	логическая 1
    x	неопределен
    z	высокоимпедансное состояние
    ------------------------------------

но еще есть такой параметр как strength:
    ------------------------------------
    supply	driving		strongest
    strong	driving             ^
    pull	driving             |
    large	storage             |
    weak	driving             |
    medium	storage             |
    small	storage             |
    highz	high impedance	weakest
    -------------------------------------

Resolution table для Verilog (когда есть электрическое соединение)

 -----------
    0 1 X Z
 -----------
0   0 X X 0
1   X 1 X 1
X   X X X X
Z   0 1 X Z
 -----------

and:
 -----------
    0 1 X Z
 -----------
0   0 0 0 0
1   0 1 X X
X   0 X X X
Z   0 X X X
 -----------

or:
 -----------
    0 1 X Z
 -----------
0   0 1 X X
1   1 1 1 1
X   X 1 X X
Z   X 1 X X
 -----------

xor:
 -----------
    0 1 X Z
 -----------
0   0 1 X X
1   1 0 X X
X   X X X X
Z   X X X X
 -----------


4.2. ПАССИВНЫЕ ЭЛЕКТРИЧЕСКИЕ КОМПОНЕНТЫ

  Резистор

Резистор (Resistor)

Закон Ома:
I = V / R

    I - сила тока	   [А]
    V - напряжение     [В]
    R - сопротивление  [Ом]

V = I * R

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

                 L
    R = P * --- , где
             S

    P - удельное электрическое сопротивление материала [Ом * м]
    L - длинна резистивного слоя [м]
    S - площадь резестивного слоя [м^2]

Удельное сопротивление: Ом * м

    --------------------------------------
    серебро		1.59  * 10^-8
    медь		1.68  * 10^-8
    алюминий        2.65  * 10^-8
    вольфрам	5.6   * 10^-8
    железо		9.71  * 10^-8
    платина		10.6  * 10^-8
    ртуть		98    * 10^-8
    нихром		100   * 10^-8  (сплав Ni,Fe,Cr)
    графит		3-66  * 10^-5
    германий	1-500 * 10^-3
    кремний		0,1-60
    стекло		10^9-10^12
    резина		10^13-10^15
    --------------------------------------

Мощность - скорость преобразования энергии

        dE     dQ
    P = --  =  -- V = IV
        dt	   dt

    P - мощность [Bт]
    E - энергия  [Дж]
    Q - заряд (количество электричества) [Кл]

для резистора:

    P = I (IR) = I^2 * R

             V         V^2
    P = --- * V =  ---
         R          R

VHDL-AMS модель резистора:

    LIBRARY IEEE;
    USE IEEE.ELECTRICAL_SYSTEMS.ALL;

    ENTITY R IS
        PORT (QUANTITY R : RESISTANCE := 1.0e+3;
              TERMINAL p,m : ELECTRICAL);
    END ENTITY R;

    ARCHITECTURE behav OF R IS
        QUANTITY v ACROSS i THROUGH p TO m;
    BEGIN
        v == i*R;
    END ARCHITECTURE behav;

Verilog-AMS модель резистора:

    module resistor1(p, n);
    inout p, n;
    electrical p, n;
    parameter real r=1 exclude 0;

    analog begin
        I(p,n) <+ V(p,n)/r;
    end
    endmodule

Последовательное соединение резисторов:

R_SERIAL
    R total= R1+R2

SPICE:
---------------------------------------------------------------

* Voltmeter(s)
R_vm_0 0 2 1MEGohm

* Ammeter(s)
*
X_ammeter_0 0 3 ammeter_1mohm

* Battery(s)
*
V1 1 0 DC 10

* Resistor(s)
*
R1 1 2 1K
*
R2 2 3 1K

* Misc
.OP

.SUBCKT ammeter_1mohm 1 2
    R 1 3 1mohm
    V 3 2 DC 0V
.ENDS

.END

---------------------------------------------------------------

Паралельное соединение резисторов:

R_PARALLEL
    R total= 1 / (1/R1+1/R2)

SPICE:
---------------------------------------------------------------

* Ammeter(s)
*
X_ammeter_0 0 2 ammeter_1mohm

* Battery(s)
*
V1 1 0 DC 10

* Resistor(s)
*
R1 1 2 1K
*
R2 1 2 1K

* Misc
.OP
.SUBCKT ammeter_1mohm 1 2
    R 1 3 1mohm
    V 3 2 DC 0V
.ENDS

.END

---------------------------------------------------------------

  Конденсатор

Конденсатор (Capacitor)

Как работает?
Как склад заряда.
На обкладках собираются заряды разных знаков.
не утекают за счет того что притягиваются друг к другу.

I= C * dV/dt

    С  - емкость конденсатора [Ф]

     Q
C = ---
     V

    Q  - заряд на конденсаторе  [Кл]

для плоского конденсатора:
С = E0 * K * S / D

    E0 - удельная диэлектрическая проницаемость ваккума [Кл*м]
         E0 = 8.85 * 10^-12 [Ф/м = Кл*м]
    K  - относительная удельная диэлектрическая проницаемость
         диэлектрика (E > 1) [1]
    S  - площадь обкладки конденсатора [м^2]
    D  - расстояние между обкладками конденсатора [м]

Энергия запасенная конденсатором равна:

             1   Q^2
    E =  - * --- = C * V^2 / 2 = Q*V/2
         2    C

Относительная диэлектрическая проницаемость:

    ------------------------
    гелий		1.00007
    воздух		1.00025
    бензин		2
    масло трансф.   2.2
    полиэтилен	2.3-2.4
    алмаз		5.7
    cлюда		5.8-7.2
    стекло		4-16
    спирт		26
    глицерин	43
    вода		81
    титанат бария	1200
    ------------------------

VHDL-AMS модель конденсатора:

    LIBRARY IEEE;
    USE IEEE.ELECTRICAL_SYSTEMS.ALL;

    ENTITY C IS
        GENERIC (V0 : VOLTAGE := 0.0);
        PORT (QUANTITY C : CAPACITANCE := 1.0e-6;
              TERMINAL p,m : ELECTRICAL);
    END ENTITY C;

    ARCHITECTURE behav OF c IS
        QUANTITY v ACROSS i THROUGH p TO m;
        QUANTITY temp_charge : CHARGE := C*V0;
    BEGIN
        IF (domain = quiescent_domain) USE
            temp_charge == C*V0;
            v == V0;
        ELSE
            temp_charge == C * v ;
            i == temp_charge'dot;
        END USE;
    END ARCHITECTURE behav;

Verilog-AMS модель конденсатора:

    module capacitor1(p, n);
    inout p, n;
    electrical p, n;
    parameter real c=1 from [0:inf);

    analog begin
            I(p,n) <+ c*ddt(V(p,n));
    end
    endmodule

Последовательное и паралельное соединение конденсаторов:

C_SERIAL
    C total= C1 * C2 / (C1 + C2)

C_PARALLEL
    C total = C1 + C2

Промоделируем зарядку/разрядку конденсатора.

SPICE не приводим так как выключателя в нем нету.

  Катушка индуктивности

Катушка индуктивности (Inductor)

----------------------
Два конца, два кольца и посередине гвоздик?
Катушка индуктивности на 2 витка.
----------------------

V= L * dI/dt

        L - индуктивность [Гн]

Индуктивность проводника определяется его размерами:
Для однослойной катушки:

    L ~= 2l * (ln(4l/d) - 1) * 10^-3  мкГн, где

        l - длинна проводника, см
        d - диаметр катушки, cм

Мощность
                           dI
    P = I V = I * L  * --
                       dt

энергия
    dW = P dt = L I dt
         o
    W = |  dW = 1/2 * L * I^2
       o

VHDL-AMS модель катушки индуктивности:

    LIBRARY IEEE;
    USE IEEE.ELECTRICAL_SYSTEMS.ALL;

    ENTITY L IS
        GENERIC (I0 : CURRENT := 0.0);
        PORT (QUANTITY L : INDUCTANCE := 1.0e-3;
              TERMINAL p,m : ELECTRICAL);
    END ENTITY L;

    ARCHITECTURE behav OF L IS
        QUANTITY v ACROSS i THROUGH p TO m;
        QUANTITY flx : FLUX := L*I0;
    BEGIN
        IF (domain = quiescent_domain) USE
            flx == L * I0;
            i == I0;
        ELSE
            flx == L * i;
            v == flx'dot;
        END USE;
    END ARCHITECTURE behav;

Verilog-AMS модель катушки индуктивности:

    module inductor1(p, n);
    inout p, n;
    electrical p, n;
    parameter real l=1 from [0:inf);

    analog begin
        V(p,n) <+ l*ddt(I(p,n));
    end
    endmodule

Последовательное и паралельное подключение индуктивностей

L_SERIAL
    L total = L1 + L2

L_PARALLEL
    L total = L1 * L2 / (L1 + L2)

Промоделируем работу индуктивности:

SPICE:
---------------------------------------------------------------

* Oscilloscope(s)
.PROBE V(2, 0)
R_o_scope_0_0 2 0 1Tohm
.PROBE V(1, 0)
R_o_scope_0_1 1 0 1Tohm

* Function Generator(s)
V_fg_plus 2 0 DC 0V AC 10V
+PULSE(-10V 10V 0 20ns 20ns 10ms 20ms)

* Resistor(s)
*
R2 0 1 1K

* Inductor(s)
*
L2 2 1 1

.END

---------------------------------------------------------------

  Фазы на пассивных компонентах


4.3.1. ФИЗИЧЕСКИЕ ОСНОВЫ

  Строение атома и орбитали

Электроны вращаются вокруг ядра по строго определенным орбитам
не поглощая и не выделяя энергии (Первый постулат Бора).
Каждой орбите соответстует определенный уровень энергии.

На каждой орбите может находится либо один электрон, либо 2 (но с разными
спинами), либо не одного.  Принцип Паули.

Спиновое квантовое число s.
У электрона может быть s либо 1/2, либо -1/2

Рассмотрим атом водорода:
Импульс у электрона как у частицы:

    mV	, где

    m - масса электрона
    V - скорость электрона

Длинна волны электрона как волны связана с импульсом соотношением:

         h
    L = ---		(формула де Бройля)
         p

    h - постоянная Планка
    L - длинна волны электромагнитных колебаний
    p - импульс электрона

откуда:

           h
    L  = ----
         m V

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

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

                            n * h
    2 PI * r = n * L = --------, где
                            m * V

    n - натуральное число (1,2,..)
    r - радиус орбиты
    PI - константа "пи"

с другой стороны при движении электрона по орбите центробежная сила
уравновешена кулоновcкой:

    m * V^2        q^2
        ------- =  ------------------
       r	   4 * PI * E0 * r^2

    q  - заряд электрона (он же заряд протона) [мы рассматриваем атом водорода]
    E0 - диэлектрическая проницаемость вакуума

                   q^2
    m * V^2 = ------------------
            4 * PI * E0 * r

но            n * h
    V = -------------
          2 * PI * m

подставляем V^2 - получаем:

    m * n^2 * h^2         q^2
    -------------- = -----------------
    4 * PI^2 * m^2    4 * PI * E0 * r

    n^2 * h^2 * E0 * r = q^2 * PI * m

        q^2 * PI * m
    r = ---------------
         n^2 * h^2 * E0

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

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

главное квантовое число n - определяет общую энергию электрона для данной
орбитали.
               m * q^4
    Е = -  ----------
           n^2 * h^2

Орбитальное квантовое число определяет момент импульса электрона
и может принимать значения от 0 до n-1.

Что значит момент импульса на пальцах:
Если орбита электрона сферическая - то момента импульса нет.

Момент импульса при этом определяется соотношением

    p = h * SQRT(l * (l+1))

Орбитали принято называть по буквенному обозначению их орбитального квантового
числа:

    --------------
    l    орбиталь
    --------------
    0	s
    1	p
    2	d
    3	f
    4	g
    --------------

Понятно, что сферический уровень более энергитически выгодный чем несферический.
Энергетические уровни для орбиталей:

Магнитное квантовое число m определяест проекцию орбитального момента импульса
на направление магнитного поля и может принимать значения:

    (-l,..,0,...l).

Магнитное квантовое число определяет направление орбитали в пространстве
и иногда форму тоже.

Формы орбиталей в зависимости от квантовых чисел:
(n - красное, l - зеленое, m - cинее)

Заполнение энергитических уровней.
Естественно сначала заполняются уровни с меньшей энергией.

  1s < 2s < 2p < 3s < 3p < 4s < 3d < 4p < 5s < 4d < 5p < 6s < 5d < 4f < 6p < 7s < 5f

Мы видем что:
    4s < 3d
просто расщепление по l для n=3 стало больше чем расщепление по n.

эмпирическое правило Клечковсого
    орбитальная энергия повышается по мере увеличения суммы (n + l)
    при равных (n + l) меньшую энергию имеет орбиталь с меньшим n.

    это правило нарушают:
        6s < 5d < 4f
    и	7s < 6d < 5f

Правило Хунда - суммарное спиновое число подуровеня должно быть максимальным.

  Расщепление энергетических уровней

В магнитном поле:
Расщепление энергетических уровней:
(Пример атом водорода):
В магнитном поле происходит расщепление уровней.

В электричеком поле:

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

^ энергия            oo                         ooooooooo
|		    -----                   	ooooooooo
|	         /        \                     ooooooooo
|	 *o    /            \    *o             ooooooooo
|	----- 		       -----            #########
|	      \             /                   *********
|	        \    **   /                     *********
|	            -----                       *********
|                                               *********
| 	H	     H2		 H              расплывание уровней в кристалле

(* = электрон, o = незаполненое место)
H2 энергитически более выгоден чем два атома водорода.

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

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

Орбитали (орбиты с уровнями энергии):

Si	1s'2  2s'2  2p'6  3s'2  3p'2
Ge	1s'2  2s'2  2p'6  3s'2  3p'6  3d'10  4s'2  4p'2

  Зонная теория

Твердые тела имеют кристаллическую решетку.

(Алмазоподобная кристалическая решетка кремния и германия).

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

Таким образом в твердых телах имеющих кристалическую решетку - образуются зоны.
Расположение и заполенение зон определяют электропроводность материала.

Например в металах зона проводимости либо не до конца заполнена,
либо просто перекрывается с валентной зоной.

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

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

^ энергия
|
|        Металл          Диэлектрик      Полупроводник
|	+--------+	+---------+	+---------+
|	|        |	|	  |     |         |
|	|        |	+---------+     |         |
|	|        |      |#########|     +---------+
|	|********|      |#########|     |#########|
|	|********|      |#########|     +---------+
|	|********|      |#########|     |*********|
|	|********|	+---------+     |*********|
|	|********|	|*********|     |*********|
    +--------+	+---------+     +---------+

У металлов нет запрещенной зоны - электроны легко могут повышать свой
энергетический уровень и двигатся по кристаллу (проводимость).

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

У полупроводников зона запрещенная зона существует но она мала мала
(ее еще специально уменьшают за счет легирования материала).

  Легирование

Легирование - процесс добавления в кристалл атомов со свойствами отличными от
свойств атомов решетки кристалла.

Легирование N-типа: добавляем атомы с избытком электронов по сравнению с веществом
(создаем лишние электроны)
Легирование P-типа: добавляем атомы с недостатком электронов по сравнению с
веществом (создаем дырки).

Доноры и акцепторы:

Вещества применяемые для легирования кремния и германия:

Без легирования:

N-типа легирование:
(избыток электронов)

P-типа легирование
(недостаток электронов)

Когда легирование слабое (порядка 10^-6 атомов примеси) то образуется не зона
а донорный или акцепторный уровень.

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

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

Электронная и дырочная проводимость:

B зонах N типа все валентные позиции в атомах заняты и ток переносят
свободные электроны.

В зонах P типа есть вакансии (дырки) и ток переносится путем перескакивания
электрона от атома в соседний (где дырка) соответственно с образованием
дырки.

Скорость перемещения заряда гораздо больше в зонах N-типа.
(Дырки двигаются медленно).

Под действием внешнего электрического поля энергитические уровни изменяются
(так же как и в кристаллической решетке:

^ энергия
|
|       Полупроводник                   Полупроводник
|	(нет электрического             (есть электрическое
|	 поля)                           поле)
|	+---------+			+---------+
|	|         |                     |         |
|	|         |                     |         |
|	+---------+                     |         |
|	|#########|                     |         |
|	+---------+                     |         |
|	|*********|                     |*********|
|	|*********|                     |*********|
|	|*********|                     |*********|
|	+---------+                     +---------+
|				уровни размылись, запрещенная зона исчезла
                появилась проводимость.

Сопротивление:

Ширина зоны у диэлектриков:

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


4.3.2. ДИОД

Диод - полупроводниковое устройство пропускающее ток только в одну сторону.

Обозначение диода:

Диод состоит из соприкасающихся областей с разным типом проводимости
N- (электронной) и P- (дырочной).

Рассмотрим как выглядит диод с точки зрения энергетических уровней:

Слева - зоны с высоким энергитическим уровнем, справа с низким.
Электроны свободно текут с горки. (Диод пропускает ток в одном направлении).
А на горку им забиратся трудно. Ток не идет.
С другой стороны если приложить большое напряжение электроны полезут на
горку - возникнет пробой.

Гетеропереходы:

  Diode Forward bias:

Электроны стремятся к +, т.к. имеют заряд -. Идут в зону контакта.
Дырки стремятся к -, т.к. имеют заряд +. Идут в зону контакта.
Они соединяются в зоне контакта, течет ток.

  Diode Reverse bias:

Электроны стремятся к +, т.к. имеют заряд -. Идут прочь от зоны контакта.
Дырки стремятся к -, т.к. имеют заряд +. Идут прочь от зоны контакта.
В результате в диоде возникает электрическое поле уравновешивающее внешнее
ток не течет.
Если же приложить слишком большое напряжение диод не сможет создать
противодействующее поле и наступит пробой.

Вольт-Амперная характеристика (ВАХ) диода:

Поведение диода описывается уравнением Эберса-Молла для диода.

    I = Io * ( e^[V/Ut] - 1 ), где

    Io - обратный ток насыщения диода  [А]
    V  - напряжение на гетеропереходе  [В]
    Ut - тепловой потенциал
         при температуре T = 300'K имеет значение порядка 25 мВ
    e  - число е (основание натурального логарифма [1]

Практически уже при напряжении порядка V = 0.1 В формула упрощается до

    I = Io * e^(V/Ut)

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

                   V - I*R
    I = Io e^(---------),   где R - сопротивление гетероперехода.
                     Ut

типичное падение напряжение на диоде:

    0.3V	Ge
    0.7V	Si

VHDL-AMS модель диода:

    LIBRARY IEEE;
    USE IEEE.ELECTRICAL_SYSTEMS.ALL;
    USE IEEE.MATH_REAL.ALL;

    ENTITY D IS
        GENERIC (ISAT : CURRENT := 1.0e-12;
                         VT : VOLTAGE := 35.0e-3;
                         RR : RESISTANCE := 100.0e3);
                         VF : VOLTAGE := 0.8;
                         RB : RESISTANCE := 1.0e3);
        PORT (TERMINAL p,m : ELECTRICAL);
    END ENTITY D;

    ARCHITECTURE behav OF D IS
        QUANTITY v ACROSS i THROUGH p TO m;
    BEGIN
        IF (v >= 0.0) USE
            i == ISAT * ((exp(v/VT)) - 1.0);
        ELSE
            i == v/RR;
        END USE;
    END ARCHITECTURE behav;

Пример диода в микросхеме:

  Моделирование:

SPICE:
----------------------------------------------------------------

* Oscilloscope(s)
.PROBE V(2, 0)
R_o_scope_0_0 2 0 1Tohm
.PROBE V(1, 0)
R_o_scope_0_1 1 0 1Tohm

* Function Generator(s)
V_fg_plus 2 0 DC -1V AC 10V
+SIN(-1V 10V 17Hz)

* Resistor(s)
*
R1 0 1 1K

* Diode(s)
*
D1 2 1 D_ideal

.MODEL D_ideal D(Is=10f Rs=0 Cjo=0 Vj=1 Tt=0 M=500m BV=1e+30 N=1 EG=1.11
+XTI=3 KF=0 AF=1 FC=500m IBV=1m TNOM=27)

.END

----------------------------------------------------------------


4.3.3. ТРАНЗИСТОР БИПОЛЯРНЫЙ (BJT)

Биполярный транзистор (BJT):
BJT - Bipolar Junction Transistor

Что такое транзистор вообще?

транзистор - как электронный ключ, когда приложено напряжение к A,
ток течет через B-C  (n-типа)
[Это очень примитивная модель в реальной жизни все гораздо сложнее]

(это биполярный транзистор NPN)

(p-типа) когда напряжение приложено к А ток не течет через B-C.

(это биполярный транзистор PNP).

Структура:

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

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

для NPN:

В NPN транзисторе электроны, основные носители тока в эмиттере проходят через
открытый переход эмиттер-база в область базы.
Часть этих электронов рекомбинирует с основными носителями заряда в базе (дырками),
часть диффундирует обратно в эмиттер.
Однако, из-за того что базу делают очень тонкой и очень слабо легированной,
большая часть электронов, инжектированная из эмиттера диффундирует в область
коллектора.
Сильное электрическое поле обратно смещённого коллекторного перехода захватывает
электроны (напомним, что они неосновные носители в базе, поэтому для них переход
открыт), и проносит их в коллектор.
Ток коллектора, таким образом, практически равен току эмиттера,
за исключением небольшой потери на рекомбинацию в базе, которая и образует ток базы

    Iэ = Iб+Iк.

Коэффициент a, связывающий ток эмиттера и ток коллектора

    Iк = a * Iэ

    a = Iк / Iэ

называется коэффициентом передачи тока эмиттера.
Численное значение коэффициента a =  0.9 - 0.999, чем больше коэффициент,
тем лучше транзистор.

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

    b = a/(1-a)  = 10-1000.

    b = Iк / Iб

Изменяя малый ток базы можно управлять значительно большим током коллектора.

для PNP:
все также но слова электроны заменяем на дырки, и так же меняем все напряжения
на противоположные по знаку.

Рассмотрим что из себя представляет транзистор с точки зрения энергетических
уровней:

Справа и слева практически одинаковые энергtтическиу уровни, а посредине
находится горка. Подводя ток к затвору мы создаем электрическое поле
которое (в зависимости от типа транзистора) или поднимает или опускает
энергетический уровень горки, в результате ток не течет или течет.

для NPN движение основных носителей заряда:

Таким образом BJT - управляется током.
Сила тока зависит пропорционально от величины тока базы - чем больше
даем носителей тем сильнее ток.

BJT можно рассматривать как переменный резистор управляемый током базы.

Промоделируем NPN BJT:

(у красного маштаб в 2 раза меньше чем у синего!)

SPICE:
----------------------------------------------------------------

* Oscilloscope(s)
.PROBE V(3, 0)
R_o_scope_0_0 3 0 1Tohm
.PROBE V(1, 0)
R_o_scope_0_1 1 0 1Tohm

* Function Generator(s)
V_fg_plus 3 0 DC 0V AC 5V
+PULSE(-5V 5V 0 500ms 500ms 1us 1s)

* Battery(s)
*
V1 4 0 DC 12

* Resistor(s)
*
R1 0 1 1K

* NPN Transistor(s)
*
Q1 4 3 1 Qnideal

.MODEL Qnideal NPN(Is=1e-16 BF=100 BR=1 Rb=0 Re=0 Rc=0 Cjs=0 Cje=0 Cjc=0
+Vje=750m Vjc=750m Tf=0 Tr=0 mje=330m mjc=330m VA=1e+30 ISE=0 IKF=1e+30
+Ne=1.5 NF=1 NR=1 VAR=1e+30 IKR=1e+30 ISC=0 NC=2 IRB=1e+30 RBM=0 XTF=0
+VTF=1e+30 ITF=0 PTF=0 XCJC=1 VJS=750m MJS=0 XTB=0 EG=1.11 XTI=3 KF=0 AF=1
+FC=500m TNOM=27)

.END

----------------------------------------------------------------

Промоделируем PNP BJT:

SPICE:
----------------------------------------------------------------

* Oscilloscope(s)
.PROBE V(1, 0)
R_o_scope_0_0 1 0 1Tohm
.PROBE V(2, 0)
R_o_scope_0_1 2 0 1Tohm

* Function Generator(s)
V_fg_plus 1 0 DC 0V AC 5V
+PULSE(-5V 5V 0 500ms 500ms 1us 1s)

* Battery(s)
*
V1 0 3 DC 12

* Resistor(s)
*
R1 0 2 1K

* PNP Transistor(s)
*
Q1 2 1 3 Qpideal

.MODEL Qpideal PNP(Is=1e-16 BF=100 BR=1 Rb=0 Re=0 Rc=0 Cjs=0 Cje=0 Cjc=0
+Vje=750m Vjc=750m Tf=0 Tr=0 mje=330m mjc=330m VA=1e+30 ISE=0 IKF=1e+30
+Ne=1.5 NF=1 NR=1 VAR=1e+30 IKR=1e+30 ISC=0 NC=2 IRB=1e+30 RBM=0 XTF=0
+VTF=1e+30 ITF=0 PTF=0 XCJC=1 VJS=750m MJS=0 XTB=0 EG=1.11 XTI=3 KF=0 AF=1
+FC=500m TNOM=27)

.END

----------------------------------------------------------------

Поведение транзистора в первом приближении описывается уравнением Эберса-Молла
для транзистора:

    Iк = Iкб.o * [ e^(Vбэ / Ut) - 1], где

    Iк    - ток через коллектор,
    Iкб.о - обратный ток насыщения гетероперехода коллектор-база
    Vбэ   - напряжение между базой и эммитером
    Ut    - тепловой потенциал

В режиме насыщения получаем:

    Iэ = (b + 1) * Iб

Зависимость тока коллектора от Vэк при различных Vбэ:

Режимы работы BJT
Каждый из гетеропереходов может быть либо открыт, либо закрыт.

    --------------------------------
            гетеропереход
    Режим работы	ЭП	КП
    --------------------------------
    Активный	+	-
    Инверсный	-	+
    Насыщения	+	+
    Отсечки		-	-
    --------------------------------

VHDL-AMS модель NPN BJT:

    PACKAGE electricalSystem IS
            NATURE electrical IS real ACROSS real THROUGH;
            FUNCTION SIN(X : real) RETURN real;
            FUNCTION EXP(X : real) RETURN real;
    END PACKAGE electricalSystem;

    use work.electricalsystem.all;

    entity bjt_npn is
          generic(isat : real := 1.0e-16;   -- Saturation Current
                  bf : real := 100.0;       -- Ideal maximus forward current
                  br : real := 1.0;         -- ideal maximum reverse current
                  rb : real := 1.0e-5;      -- Base resistance
                  rc : real := 1.0e-5;      -- collector resistance
                  re : real := 1.0e-5;      -- emmiter resistance
                  vaf : real := 100.0);     -- Forward Early Voltage
          port(terminal e,b,c : electrical);
    end bjt_npn;

    architecture structure of bjt_npn is
          terminal b1, c1, e1 : electrical;
          quantity vbo across ib through b to b1;
          quantity vco across ic through c to c1;
          quantity veo across ie through e to e1;
          quantity vct across Ict through c1 to e1;--current source
          quantity vbe across ibe through b1 to e1;
          quantity vbc across ibc through b1 to c1;
          quantity vce : real := 1.0;     -- used to calculate VCE
          constant gmin : real := 1.0e-12;-- condutsnce in parallel with every pn junction
          constant vt : real := 0.02589;  -- thermal voltage
    begin
        brk : break vbe => 1.0, vbc => -1.0;
   diodecond1 : if(vbe > -5.0*vt) use
                diodebef : ibe == ((isat*(exp(vbe/vt) - 1.0)) + (gmin*vbe))/bf;
          elsif(vbe <= -5.0*vt ) use
                diodeber: ibe == ((-1.0*isat) + (gmin*vbe))/bf;
          end use;
  diodecond2 :  if(vbc > -5.0*vt) use
                diodebcf : ibc == ((isat*(exp(vbc/vt) - 1.0)) + (gmin*vbc))/br;
          elsif(vbc <= -5.0*vt) use
                diodebcr : ibc == ((-1.0*isat) + (gmin*vbc))/br;
          end use;
          bres : vbo == ib * 1.0e-6;
          cres : vco == ic * 1.0e-6;
          eres : veo == ie * 1.0e-6;
          kcl_eqn : ie == -1.0*(ib + ic);
          vcevolt : vce == vbe - vbc;
          ictdep : Ict == ((Ibe*bf) - (Ibc*br)) * (1.0 -(vbc/vaf));
    end architecture structure;

VHDL-AMS модель PNP BJT:

    PACKAGE electricalSystem IS
            NATURE electrical IS real ACROSS real THROUGH;
            FUNCTION SIN(X : real) RETURN real;
            FUNCTION EXP(X : real) RETURN real;
    END PACKAGE electricalSystem;

    use work.electricalsystem.all;

    entity bjt_pnp is
          generic(isat : real := 1.0e-16;   -- Saturation Current
                  bf : real := 100.0;       -- Ideal maximus forward current
                  br : real := 1.0;         -- ideal maximum reverse current
                  rb : real := 1.0e-5;      -- Base resistance
                  rc : real := 1.0e-5;      -- collector resistance
                  re : real := 1.0e-5;      -- emmiter resistance
                  vaf : real := 100.0);     -- Forward Early Voltage
          port(terminal e,b,c : electrical);
    end bjt_pnp;

    architecture structure of bjt_pnp is
          terminal b1, c1, e1 : electrical;
          quantity vbo across ib through b1 to b;
          quantity vco across ic through c1 to c;
          quantity veo across ie through e1 to e;
          quantity vct across Ict through e1 to c1;--current source
          quantity vbe across ibe through e1 to b1;
          quantity vbc across ibc through c1 to b1;
          quantity vce : real := 1.0;           -- used to calculate VCE
          constant gmin : real := 1.0e-12;      -- condutsnce in parallel with every pn junction
          constant vt : real := 0.02589; -- thermal voltage
    begin
        brk : break vbe => 1.0, vbc => -1.0;
   diodecond1 : if(vbe > -5.0*vt) use
                diodebef : ibe == ((isat*(exp(vbe/vt) - 1.0)) + (gmin*vbe))/bf;
          elsif(vbe <= -5.0*vt ) use
                diodeber: ibe == ((-1.0*isat) + (gmin*vbe))/bf;
          end use;
   diodecond2 : if(vbc > -5.0*vt) use
                diodebcf : ibc == ((isat*(exp(vbc/vt) - 1.0)) + (gmin*vbc))/br;
          elsif(vbc <= -5.0*vt) use
                diodebcr : ibc == ((-1.0*isat) + (gmin*vbc))/br;
          end use;
          bres : vbo == ib * 1.0e-6;
          cres : vco == ic * 1.0e-6;
          eres : veo == ie * 1.0e-6;
          kcl_eqn : ie == -1.0*(ib + ic);
          vcevolt : vce == vbe - vbc;
          ictdep : Ict == ((Ibe*bf) - (Ibc*br)) * (1.0 -(vbc/vaf));
    end architecture structure;


4.3.4. ТРАНЗИСТОР ПОЛЕВОЙ (JFET)

JFET - Junction Field Electric Transistor
Полевой транзистор - управляется электрическим полем

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

JFET состоит из узкой области одного типа проводимости, окруженной
областью другово типа проводимости.
В этой узкой области путем приложения напряжение к более большой области
формируется поле, мешающее передвижению зарядов.

Таким образом в отличии от BJT JFET управляется полем

VHDL-AMS модель N-JFET:

    PACKAGE electricalSystem IS
            NATURE electrical IS real ACROSS real THROUGH;
            FUNCTION POW(X,Y: real) RETURN real;
            FUNCTION SIN(X : real) RETURN real;
            FUNCTION EXP(X : real) RETURN real;
            FUNCTION SQRT(X : real) RETURN real;
    END PACKAGE electricalSystem;

    use work.electricalsystem.all;

    entity njfet is
            generic(T : real := 300.0;
                vto : real := -2.0;    -- Zero-bais threshold voltage
                beta : real := 1.0e-4; -- transconductance parameter
                lambda : real := 0.0;  -- channel lenght modulation
                af : real := 1.0;      -- flicker noise exponent
                kf : real := 0.0;      -- flicker noise coefficient
                iss : real := 1.0e-14; -- gate junction saturation current
                pb : real := 1.0;      -- gate junction potential
                fc : real := 0.5;      -- forward-bais depletion capacitance coeff
                cgd : real := 4.0e-11; -- zero-bais gate-drain junction cap
                cgs : real := 4.0e-11; -- zero-bias gate-source junction cap
                rd : real := 1.0e-6;   -- drain ohmic resistance
                rs : real := 1.0e-6);  -- source ohmic resistance
            port (terminal g,s,d : electrical);
    end entity njfet;

    architecture behav of njfet is
          terminal d1, s1 : electrical;
          quantity vds across id through d1 to s1;
          quantity vrd across ird through d to d1;
          quantity vrs across irs through s1 to s;
          quantity vgs across igs through g to s1;
          quantity vgd across igd through g to d1;
          constant gmin : real := 1.0e-12;
          quantity ktq : real := 2.586e-2; -- (kT/q) thermal voltage at T=300K
          quantity vds_free : real := 2.0;
          quantity vgs_free : real := 0.0;
          quantity vgd_free : real := 2.0;
    begin
          ------ Setting initial conditions
          initreg : break vgs => 0.0, vds => 2.0, vgd => 2.0;
          therm_volt : ktq == 2.586e-2 * (T/300.0);
          dres : vrd == ird * rd;
          oup_res : vds_free == vds;
          inp_res : vgs_free == vgs;
          vgdf : vgd_free == vgd;
          sres : vrs == irs * rs;

    ---- Current is in Amps.
    -- Normal mode
          ------ Cut off Region
      regions : if((vgs <= vto) and (vds >= 0.0))use
            gncn : id == 1.0e-9 * vds;
          ------ Linear Region
          elsif((vds < (vgs-vto)) and (vgs > vto) and (vds >= 0.0)) use
                  gnln : id == vds*beta*((2.0*(vgs_free-vto)) - vds_free)*(1.0 + lambda*vds_free);
          ------ Saturation Region
          elsif((vds >= vgs-vto) and (vgs > vto) and (vds >= 0.0)) use
                 gnsn : id == beta*(pow((vgs_free-vto),2.0))*(1.0 + lambda*vds_free);
    -- Inversted mode
          ------ Cut off Region
          elsif((vgd <= vto) and (vds < 0.0))use
            gnci : id == 1.0e-9 * vds;
          ------ Linear Region
          elsif(((-1.0*vds) < (vgd-vto)) and (vgd > vto) and (vds < 0.0)) use
                  gnli : id == vds*beta*((2.0*(vgd_free-vto)) + vds_free)*(1.0 - lambda*vds_free);
          ------ Saturation Region
          elsif(((-1.0*vds) >= vgd-vto) and (vgd > vto) and (vds < 0.0)) use
                 gnsi : id == -1.0*(beta)*(pow((vgd_free-vto),2.0))*(1.0 - lambda*vds_free);
          end use;

    ----- Gate diode equations
          initsub : break vgd => 0.0, vgs => 0.0, igs => 0.0, igd => 0.0;

           ----- Gate to source
           subcond1 : if(vgs > -5.0*ktq) use
            gsf : igs == ((iss*(exp(vgs/ktq) - 1.0)) + (gmin*vgs));
           elsif(vgs <= -5.0*ktq ) use
               gsr : igs == -1.0*iss + (gmin*vgs);
           end use;
           ----- Gate to drain
           subcond2 : if(vgd > -5.0*ktq) use
            gdf : igd == ((iss*(exp(vgd/ktq) - 1.0)) + (gmin*vgd));
           elsif(vgd <= -5.0*ktq ) use
                gdr : igd == -1.0*iss + (gmin*vgd);
           end use;
    end architecture behav;

VHDL-AMS модель P-JFET:

    PACKAGE electricalSystem IS
            NATURE electrical IS real ACROSS real THROUGH;
            FUNCTION POW(X,Y: real) RETURN real;
            FUNCTION SIN(X : real) RETURN real;
            FUNCTION EXP(X : real) RETURN real;
            FUNCTION SQRT(X : real) RETURN real;
    END PACKAGE electricalSystem;

    use work.electricalsystem.all;

    entity pjfet is
            generic(T : real := 300.0;
                vto : real := -2.0;   -- Zero-bais threshold voltage
                beta : real := 1.0e-4; -- transconductance parameter
                lambda : real := 0.0;  -- channel lenght modulation
                af : real := 1.0;      -- flicker noise exponent
                kf : real := 0.0;      -- flicker noise coefficient
                iss : real := 1.0e-14; -- gate junction saturation current
                pb : real := 1.0;      -- gate junction potential
                fc : real := 0.5;      -- forward-bais depletion capacitance coeff
                cgd : real := 4.0e-11; -- zero-bais gate-drain junction cap
                cgs : real := 4.0e-11; -- zero-bias gate-source junction cap
                rd : real := 1.0e-6;   -- drain ohmic resistance
                rs : real := 1.0e-6);  -- source ohmic resistance
            port (terminal g,s,d : electrical);
    end entity pjfet;

    architecture behav of pjfet is
          terminal d1, s1 : electrical;
          quantity vds across id through s1 to d1;
          quantity vrd across ird through d1 to d;
          quantity vrs across irs through s to s1;
          quantity vgs across igs through s1 to g;
          quantity vgd across igd through d1 to g;
          constant gmin : real := 1.0e-12;
          quantity ktq : real := 2.586e-2; -- (kT/q) thermal voltage at T=300K
          quantity vds_free : real := 2.0;
          quantity vgs_free : real := 0.0;
          quantity vgd_free : real := 2.0;
    begin
          ------ Setting initial conditions
          initreg : break vgs => 0.0, vds => 2.0, vgd => 2.0;
          therm_volt : ktq == 2.586e-2 * (T/300.0);
          dres : vrd == ird * rd;
          oup_res : vds_free == vds;
          inp_res : vgs_free == vgs;
          vgdf : vgd_free == vgd;
          sres : vrs == irs * rs;

        ---- Current is in Amps.
      -- Normal mode
          ------ Cut off Region
      regions : if((vgs <= vto) and (vds >= 0.0))use
            gncn : id == 1.0e-9 * vds;
          ------ Linear Region
          elsif((vds < (vgs-vto)) and (vgs > vto) and (vds >= 0.0)) use
                  gnln : id == vds*beta*((2.0*(vgs_free-vto)) - vds_free)*(1.0 + lambda*vds_free);
          ------ Saturation Region
          elsif((vds >= vgs-vto) and (vgs > vto) and (vds >= 0.0)) use
                 gnsn : id == beta*(pow((vgs_free-vto),2.0))*(1.0 + lambda*vds_free);

    -- Inversted mode
          ------ Cut off Region
          elsif((vgd <= vto) and (vds < 0.0))use
            gnci : id == 1.0e-9 * vds;
          ------ Linear Region
          elsif(((-1.0*vds) < (vgd-vto)) and (vgd > vto) and (vds < 0.0)) use
                  gnli : id == vds*beta*((2.0*(vgd_free-vto)) + vds_free)*(1.0 - lambda*vds_free);
          ------ Saturation Region
          elsif(((-1.0*vds) >= vgd-vto) and (vgd > vto) and (vds < 0.0)) use
                 gnsi : id == -1.0*(beta)*(pow((vgd_free-vto),2.0))*(1.0 - lambda*vds_free);
          end use;

   ----- Gate diode equations
          initsub : break vgd => 0.0, vgs => 0.0, igs => 0.0, igd => 0.0;

           ----- Gate to source
         subcond1 : if(vgs > -5.0*ktq) use
            gsf : igs == ((iss*(exp(vgs/ktq) - 1.0)) + (gmin*vgs));
           elsif(vgs <= -5.0*ktq ) use
               gsr : igs == -1.0*iss + (gmin*vgs);
           end use;
           ----- Gate to drain
           subcond2 : if(vgd > -5.0*ktq) use
            gdf : igd == ((iss*(exp(vgd/ktq) - 1.0)) + (gmin*vgd));
           elsif(vgd <= -5.0*ktq ) use
                gdr : igd == -1.0*iss + (gmin*vgd);
           end use;
    end architecture behav;


4.3.5. MOSFET ТРАНЗИСТОР

MOSFET - Metal-Oxide-Semiconductor FET

Металл-Оксид-Полупроводник (МОС) транзистор является основным полупроводниковым
прибором в наши дни. Микросхемы содержат десятки миллионов MOSFET транзисторов.

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

MOSFET состоит из стока, истока и затвора который покрывает узкую
приповерхностную полосу канала, по которому течет электрический ток.
Затвор (металический) изолирован от канала слоем диэлектрика (оксида кремния SiO2)

поликристалический SiO2 и кристалический Si:

символы для обогащенные MOSFET:

символы для обедненые MOSFET:
(хотя в общем-то обедненные PMOS практически не делают)

В зависимости от типа проводимости канала бывают MOSFET N- и P- типа.

MOSFET N-типа

MOSFET N-типа

MOSFET P-типа

MOSFET P-типа

MOSFET можно рассматривать как управляемый резистор.
Через затвор протекает только очень малый ток утечки, затвор имеет
очень высокое сопротивлении, поэтому MOSFET управляется напряжением.

Действует формула

    Ic = k (Vзи - Vп)^2, где

    Ic  - ток стока
    k   - коэфициент пропорциональности
    Vзи - напряжение затвор-исток
    Vп  - пороговое напряжение открытия MOSFET

В зависимости от степени легирования MOSFET бывают обогащенные и
обедненные. Разница между ними в наличии пропускания некоторого набольшого
тока при отсутствии напряжения на затворе.

У обогащенного FET при отсутствии напряжения на затворе может протекать
некоторый ток.
А у обедненного нет.

Меняя степень легирования можно менять характеристики MOSFETа:

MOSFET: (транзистор управляемый полем):
                        +-------------+
            |  затвор     |
    -----------+    +-------------+	   +-----------
    исток	   |	|  оксид      |    | сток
    -----------+----+-------------+----+-----------
        |         полупроводник      |
        +----------------------------+
        |         изолятор           |
        +----------------------------+
        |	   подложка	     |
        +----------------------------+

когда между затвором и подложкой разница потенциалов возникает электрическое
поле и ток течет от истока к стоку, когда разницы потенциалов нет, то
ток практически не течет (сопротивление около 10**6 Ом).

MOS-транзисторы (Metal Oxide Semiconductor)

NMOS транзистор:

Обозначение переключателя на NMOS транзисторе
(когда к затвору приложено напряжение ток течет).

Имплементация NMOS транзистора:

PMOS транзистор:

Обозначение переключателя на PMOS транзисторе
(когда к затвору приложено напряжение ток не течет).

Имплементация PMOS транзистора:

ВАХ для N-MOSFET (0.25):

ВАХ для P-MOSFET (0.25):

  Моделирование MOS транзисторов на Verilog HDL.

Verilog VHDL позволяет моделировать NMOS и PMOS транзисторы на цифровом
уровне (транзисторы рассматриваются как переключатели).

Таблица истинности для Verilog NMOS транзистора

    nmos(out, in, control);

    ---------------------
    NMOS |  control
    data |  0  1  x  z
    -----+--------------
      0  |  z  0  L  L
      1  |  z  1  H  H
      x  |  z  x  x  x
      z  |  z  z  z  z
    ---------------------

Таблица истинности для Verilog PMOS транзистора

    pmos(out, in, control);

    ---------------------
    PMOS |  control
    data |  0  1  x  z
    -----+--------------
      0  |  0  z  L  L
      1  |  1  z  H  H
      x  |  x  z  x  x
      z  |  z  z  z  z
    ---------------------

VHDL-AMS модель N-MOSFET:

    PACKAGE electricalSystem IS
            NATURE electrical IS real ACROSS real THROUGH;
            FUNCTION POW(X,Y: real) RETURN real;
            FUNCTION SIN(X : real) RETURN real;
            FUNCTION EXP(X : real) RETURN real;
            FUNCTION SQRT(X : real) RETURN real;
    END PACKAGE electricalSystem;

    use work.electricalsystem.all;

    entity nmos is
            generic(mos_type : real := 1.0; -- +1.0 for nmos , -1.0 for pmos
                T : real := 300.0;
                W : real := 1.0;
                L : real := 1.0;
                vto : real := 1.0;   -- Zero-bais threshold voltage
                kp : real := 2.0e-5; -- transcondiuctanec parameter
                gamma : real := 0.0; -- body-effect parameter
                phi : real := 0.6;   -- surface inversion potential
                lambda : real := 0.02; -- channel lenght modulation
                tox : real := 1.0e-7; -- thin oxide thickness
                nsub : real := 0.0;   -- Substrate doping
                nss : real := 0.0;    -- Surface STate density
                ld : real := 0.0;     -- lateral diffusion;
                tpg : real := 1.0;    -- Type of Gate material
                uo : real := 600.0;   -- Surface mobility
                af : real := 1.0;     -- flicker noise exponent
                kf : real := 0.0;      -- fliccker noise coefficient
                iss : real := 1.0e-14; -- bulk junction saturation current
                js : real := 0.0;    -- bulk junctioin saturatioin current/ sqr meter
                pb : real := 0.80;   -- bulk junction potential
                cj : real := 0.0;    -- Zero-bias bulk capacitance/ sqr meter
                mj : real := 0.5;    -- bulk junctioin grading coefficient
                cjsw : real := 0.0;   -- Zero bias perimeter capacitance / sqr meter
                mjsw : real := 0.33; -- Perimiter capacitance rading coefficient
                fc : real := 0.5; -- forward-bais depletion capacitance coeff
                cgbo : real := 2.0e-10; -- gate-bulk overlap cap / meter
                cgdo : real := 4.0e-11; -- gate-drain overlap cap / meter
                cgso : real := 4.0e-11; -- gate-source overlap cap / meter
                rd : real := 1.0; -- drain ohmic resistance
                rs : real := 1.0; -- source ohmic resistance
                rsh : real := 0.0); -- source and drain sheet resistance
            port (terminal g,s,d,b : electrical);
    end entity nmos;

    architecture behav of nmos is
          terminal d1, s1 : electrical;
          quantity vds across idsg through d1 to s1;
          quantity vdsr across idsr through d1 to d;
          quantity vgs across igs through g to s1;
          quantity vbs across ibs through b to s1;
          quantity vbd across ibd through b to d1;
          quantity vsr across isr through s1 to s;
          quantity iss, isd : real := 1.0e-12;
          quantity beta : real := 8.85e-05;  -- gain
          quantity leff : real := 1.0;       -- effective length
          constant gmin : real := 1.0e-12;
          quantity vth : real := 0.5;        -- threshold voltage
          quantity ktq : real := 2.586e-2; -- (kT/q) thermal voltage at T=300K
          constant cox_prime : real := 3.4515e-8; -- oxide capacitance per unit area F/cm2. cox_prime = EOX/TOX
          quantity cox : real := 3.4515e-8;
          quantity vds_free : real := 5.0;
          quantity vgs_free : real := 0.0;
          constant as : real := 15.0e-12; -- source area
          constant ad : real := 15.0e-12; -- drain area
    begin
          ------ Setting initial conditions
          initreg : break vgs => 0.0, vbs => 0.0, vth => 0.5;
         thres_volt : vth == vto + (gamma *(sqrt((2.0*phi)-vbs) - sqrt(phi)));
          eff_length : leff == L - (2.0*ld);
          therm_volt : ktq == 2.586e-2 * (T/300.0);
          sat_scurr : iss == js*as;
          sat_dcurr : isd == js*ad;
          gn : beta == kp * ( w/leff);
          d12_res : vdsr == idsr * rd;
          oup_res : vds_free == vds;
          inp_res : vgs_free == vgs;
          gre : vgs == igs * 1.0e9;
          capeqn : cox == cox_prime * W * Leff; -- cox_prime * W * Leff
          src_res : isr == vsr * rs;
    -- Normal mode
          ------ Cut off Region
          regions : if((vgs < vth) and (vds >= 0.0))use
            gncn : idsg == 1.0e-9 * vds;
          ------ Linear Region
          elsif((vds <= (vgs-vth)) and (vgs >= vth) and (vds >= 0.0)) use
                  gnln : idsg == vds*beta*((vgs_free-vth) - (vds_free/2.0))*(1.0 + lambda*vds_free);
          ------ Saturation Region
          elsif((vds > vgs-vth) and (vgs >= vth) and (vds >= 0.0)) use
                 gnsn : idsg == (beta/2.0)*(pow((vgs_free-vth),2.0))*(1.0 + lambda*vds_free);
    -- Inversion mode
          ------ Cut off Region
          elsif((vgs < vth) and (vds < 0.0))use
            gnci : idsg == 1.0e-9 * vds;
          ------ Linear Region
          elsif(((-1.0*vds) <= (vgs-vth)) and (vgs >= vth) and (vds < 0.0)) use
                  gnli : idsg == vds*beta*((vgs_free-vth) + (vds_free/2.0))*(1.0 - lambda*vds_free);
          ------ Saturation Region
          elsif(((-1.0*vds) > vgs-vth) and (vgs >= vth) and (vds < 0.0)) use
                 gnsi : idsg == -1.0*(beta/2.0)*(pow((vgs_free-vth),2.0))*(1.0 - lambda*vds_free);
          end use;
    ----- Substrate diode equations
          initsub : break vbd => 0.0, vbs => 0.0, ibs => 0.0, ibd => 0.0;
             ----- Substrate to source
           subcond1 : if(vbs > 0.0) use
            bulk1 : ibs == ((iss*(exp(vbs/ktq) - 1.0)) + (gmin*vbs));
           elsif(vbs <= 0.0 ) use
               bulk2 : ibs == ((iss*(vbs/ktq)) + (gmin*vbs));
           end use;
           ----- Substrate to drain
           subcond2 : if(vbd > 0.0) use
            bulk3 : ibd == ((isd*(exp(vbd/ktq) - 1.0)) + (gmin*vbd));
           elsif(vbd <= 0.0 ) use
                bulk4 : ibd == ((isd*(vbd/ktq)) + (gmin*vbd));
           end use;
end architecture behav;

VHDL-AMS модель P-MOSFET:

    PACKAGE electricalSystem IS
            NATURE electrical IS real ACROSS real THROUGH;
            FUNCTION POW(X,Y: real) RETURN real;
            FUNCTION SIN(X : real) RETURN real;
            FUNCTION EXP(X : real) RETURN real;
            FUNCTION SQRT(X : real) RETURN real;
    END PACKAGE electricalSystem;

    use work.electricalsystem.all;

    entity pmos is
            generic(mos_type : real := 1.0; -- +1.0 for nmos , -1.0 for pmos
                T : real := 300.0;
                W : real := 1.0;
                L : real := 1.0;
                vto : real := 1.0;   -- Zero-bais threshold voltage
                kp : real := 2.0e-5; -- transcondiuctanec parameter
                gamma : real := 0.0; -- body-effect parameter
                phi : real := 0.6;   -- surface inversion potential
                lambda : real := 0.02; -- channel lenght modulation
                tox : real := 1.0e-7; -- thin oxide thickness
                nsub : real := 0.0;  -- Substrate doping
                nss : real := 0.0;   -- Surface STate density
                ld : real := 0.0;    -- lateral diffusion;
                tpg : real := 1.0;   -- Type of Gate material
                uo : real := 600.0;  -- Surface mobility
                af : real := 1.0;    -- flicker noise exponent
                kf : real := 0.0;    -- fliccker noise coefficient
                iss : real := 1.0e-14; -- bulk junction saturation current
                js : real := 0.0;    -- bulk junctioin saturatioin current/ sqr meter
                pb : real := 0.80;   -- bulk junction potential
                cj : real := 0.0;    -- Zero-bias bulk capacitance/ sqr meter
                mj : real := 0.5;    -- bulk junctioin grading coefficient
                cjsw : real := 0.0;  -- Zero bias perimeter capacitance / sqr meter
                mjsw : real := 0.33; -- Perimiter capacitance rading coefficient
                fc : real := 0.5;    -- forward-bais depletion capacitance coeff
                cgbo : real := 2.0e-10; -- gate-bulk overlap cap / meter
                cgdo : real := 4.0e-11; -- gate-drain overlap cap / meter
                cgso : real := 4.0e-11; -- gate-source overlap cap / meter
                rd : real := 1.0;    -- drain ohmic resistance
                rs : real := 1.0;    -- source ohmic resistance
                rsh : real := 0.0);  -- source and drain sheet resistance
        port (terminal g,s,d,b : electrical);
    end entity pmos;

    architecture behav of pmos is
          terminal d1, s1 : electrical;
          quantity vds across idsg through d1 to s1;
          quantity vdsr across idsr through d1 to d;
          quantity vgs across igs through g to s1;
          quantity vbs across ibs through s1 to b;
          quantity vbd across ibd through d1 to b;
          quantity vsr across isr through s1 to s;
          quantity iss, isd : real := 1.0e-12;
          quantity beta : real := 8.85e-05; -- gain
          quantity leff : real := 1.0;      -- effective length
          constant gmin : real := 1.0e-12;
          quantity vth : real := 0.5;       -- threshold voltage
          quantity ktq : real := 2.586e-2; -- (kT/q) thermal voltage at T=300K
          constant cox_prime : real := 3.4515e-8; -- oxide capacitance per unit area F/cm2. cox_prime = EOX/TOX
          quantity cox : real := 3.4515e-8;
          quantity vds_free : real := 5.0;
          quantity vgs_free : real := 0.0;
          constant as : real := 15.0e-12; -- source area
          constant ad : real := 15.0e-12; -- drain area
    begin
          ------ Setting initial conditions
          initreg : break vgs => 0.0, vbs => 0.0, vth => 0.5;
           thres_volt : vth == vto + (gamma *(sqrt((2.0*phi)-vbs) - sqrt(phi)));
          eff_length : leff == L - (2.0*ld);
          therm_volt : ktq == 2.586e-2 * (T/300.0);
          sat_scurr : iss == js*as;
          sat_dcurr : isd == js*ad;
          gn : beta == kp * ( w/leff);
          d12_res : vdsr == idsr * rd;
          oup_res : vds_free == vds;
          inp_res : vgs_free == vgs;
          gre : vgs == igs * 1.0e9;
          capeqn : cox == cox_prime * W * Leff; -- cox_prime * W * Leff
          src_res : isr == vsr * rs;
    -- Normal mode
          ------ Cut off Region
          regions : if((vgs > vth) and (vds <= 0.0))use
            gncn : idsg == -1.0e-9 * vds;
          ------ Linear Region
          elsif((vds >= (vgs-vth)) and (vgs <= vth) and (vds <= 0.0)) use
                  gnln : idsg == -1.0*vds*beta*((vgs_free-vth) - (vds_free/2.0))*(1.0 - lambda*vds_free);
          ------ Saturation Region
          elsif((vds < vgs-vth) and (vgs <= vth) and (vds <= 0.0)) use
                 gnsn : idsg == -1.0*(beta/2.0)*(pow((vgs_free-vth),2.0))*(1.0 - lambda*vds_free);
    -- Inversion mode
          ------ Cut off Region
          elsif((vgs > vth) and (vds > 0.0))use
            gnci : idsg == -1.0e-9 * vds;
          ------ Linear Region
          elsif(((-1.0*vds) >= (vgs-vth)) and (vgs <= vth) and (vds > 0.0)) use
                  gnli : idsg == -1.0*vds*beta*((vgs_free-vth) + (vds_free/2.0))*(1.0 + lambda*vds_free);
          ------ Saturation Region
          elsif(((-1.0*vds) < vgs-vth) and (vgs >= vth) and (vds > 0.0)) use
                 gnsi : idsg == (beta/2.0)*(pow((vgs_free-vth),2.0))*(1.0 + lambda*vds_free);
          end use;

    ----- Substrate diode equations
          initsub : break vbd => 0.0, vbs => 0.0, ibs => 0.0, ibd => 0.0;
           ----- Substrate to source
           subcond1 : if(vbs > 0.0) use
            bulk1 : ibs == ((iss*(exp(vbs/ktq) - 1.0)) + (gmin*vbs));
           elsif(vbs <= 0.0 ) use
               bulk2 : ibs == ((iss*(vbs/ktq)) + (gmin*vbs));
           end use;
           ----- Substrate to drain
           subcond2 : if(vbd > 0.0) use
            bulk3 : ibd == ((isd*(exp(vbd/ktq) - 1.0)) + (gmin*vbd));
           elsif(vbd <= 0.0 ) use
                bulk4 : ibd == ((isd*(vbd/ktq)) + (gmin*vbd));
          end use;
    end architecture behav;


4.3.6. ПОЛЯРНОСТЬ ТРАНЗИСТОРОВ

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

 -------------------------------------------------------
                       выход +
            ^
                        |
                    |
      N-MOS обедненный  |   N-MOS обогащенный
      N-JFET            |   NPN-BJT
            |
- вход  ----------------+-------------------> вход +
                        |
      P-MOS обогащенный |   P-JFET
      PNP-BJT           |
            |
             выход -
 -------------------------------------------------------

n-MOSFET enhanced:

p-MOSFET enhanced:


4.4. КРЕМНЕВЫЕ ТЕХНОЛОГИИ

На базе полупроводниковых устройств рассмотренных выше созданы различные технологии
которые мы будем рассматривать в этой секции.

Кремневые технологии делятся на биполярные (используют BJT) и MOS (используют
MOSFET).

Основные биполярные технологии:
    TTL	Transistor-Transistor logic
    ECL	Emmiter coupled logic
            очень быстрая
            Кушает очень много энергии
    I2L	Integrated Injected logic
            Занимает мало места

Основные MOS технологии:
    PMOS	p-channel MOSFET enhancement
            занимает много места (p-MOSFET больше чем n-MOSFET)
    NMOS	n-channel MOSFET enhancement
    HMOS	n-channel MOSFET depletion
            Немного быстрее чем NMOS, но жрет больше энергии
    CMOS	Compimentary MOS (i.e. n- and p- enhancement MOSFET combined)
            Малое потребление энергии (только переключение)
    CHMOS	CMOS with depletion MOSFET
            Немного быстрее CMOS, но жрет больше энергии
            за счет того что небольшой ток течет не только во
            время переключений
    MNOS	Metal Nitride Oxide Semiconductor
        (используется для производства транзисторов с плавающим затвором).

Гибридные технологии:
    BiCMOS	Mix of BJT and CMOS

  BJT vs MOSFET

BJT занимают больший размер чем MOSFET.
До определенной нормы быстродействие у BJT выше.


4.4.1. ЭЛЕКТРИЧЕСКИЕ ОСНОВЫ (NMOS)

NMOS - технология логики на n-типа транзисторах.
       [N-type Metal-Oxide-Semiconductor]

  NOT

[Идея]

[NMOS]

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

[NMOS как это в реальности и происходит]

когда Vin имеет низкий уровень (т.е. 0), транзистор закрыт и на выход
приходит ток из Vcc (+5V,т.е. 1), [резистор обеспечивает только очень
небольшое падение напряжения в этом случае ~ 0.3V т.е до +4.7V]
если же Vin высокий (1), транзистор открыт и Vout получается соединенным с
землей (т.е. 0).

    -------------		----------
    Vin  | Vout             Vin | Vout  = NOT
    -----+-------           ----+-----
    0 V  | +5V              0   | 1
    +5V  | 0V               1   | 0
    -----+-------           ----+-----

Это реальная имплементация NMOS инвертора
(используются полевые транзисторы, верхний как резистор).

NMOS и PMOS инверторы:

Пример аналогового электрического моделирования инвертора:
(используем N-JFET)

Существует время прохождения сигнала через логический элемент:
(в реальном мире все происходит за конкретное время).

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

    module	nmos_not(out,in);
        output	out;
        input	in;
        wand	pull;

        supply1	pwr;
        supply0	gnd;

        assign pull = pwr;
        nmos(pull,gnd,in);
        assign out = pull;
    endmodule

  NAND

[Идея]

[NMOS идея]

[NMOS]

NAND очень похож на NOT, но Vout имеет низкий уровень только тогда, когда
открыты оба транзистора:

    --------------		-------------
    V1  V2 | Vout           V1  V2 | Vout	= NAND
    -------+------		-------+-----
    0V  0V | +5V		0   0  |  1
    0V +5V | +5V            0   1  |  1
    +5V 0V | +5V            1   0  |  1
    +5V +5V| 0V             1   1  |  0
    --------------		-------------

Пример моделирования NMOS NAND2 на Verilog:

    module	nmos_nand2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wand	pull;
        wire	x;

        assign pull = pwr;
        nmos(pull, x, a);
        nmos(x,  gnd, b);
        assign out = pull;
    endmodule

[Идея]

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

Но бесконечно усиливать число каскадов нельзя.
Современные технологии ограничивают число входов в NAND шести.
Если надо больше то идут уже не электрические схемы, а логические.

Это пример того, что знание соседнего уровня (электрического)
позволяет оптимизировать текущий (фуекционально-логический)
Т.е. мы вместо того чтобы городить каскад логики для NAND3, NAND4, NAND5,
NAND6 просто реализуем это на более нижнем уровне и выиграем в размере
кристалла.

Пример моделирования NMOS NAND3 на Verilog:

    module	nmos_nand3(out,a,b,c);
        output	out;
        input	a,b,c;

        supply1	pwr;
        supply0	gnd;
        wire	x,y;
        wand	pull;

        assign pull = pwr;
        nmos(pull, x, a);
        nmos(x,  y, b);
        nmos(y,  gnd, c);
        assign out = pull;
    endmodule

  NOR

[Идея]

[NMOS идея]

[NMOS]

Идея NOR тоже пришла из инвертора: если хотя бы один транзистор будет открыт
то Vout будет соединен с землей (т.е. 0)

    --------------		-------------
    V1  V2  | Vout          V1  V2 | Vout = NOR
    --------+-----		-------+-----
    0V   0V | +5V		 0  0  | 1
    0V  +5V | 0V             0  1  | 0
    +5V  0V | 0V             1  0  | 0
    +5V +5V | 0V             1  1  | 0
    --------------          -------------

Пример моделирования NMOS NOR2 на Verilog:

    module	nmos_nor2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wand	pull;

        assign pull = pwr;
        nmos(pull, gnd, a);
        nmos(pull, gnd, b);
        assign out = pull;
    endmodule

[Идея]

Таже идея что и в NAND используется для наращивания каскадов.
Современные технологии ограничивают число входов в NAND четырем.

Пример моделирования NMOS NOR3 на Verilog:

    module	nmos_nor3(out,a,b,c);
        output	out;
        input	a,b,c;

        supply1	pwr;
        supply0	gnd;
        wand	pull;

        assign pull = pwr;
        nmos(pull, gnd, a);
        nmos(pull, gnd, b);
        nmos(pull, gnd, c);
        assign out = pull;
    endmodule

  Buffer

[Идея - в NMOS невоплотима]

повторитель (усилитель) (buffer).

Если Vin имеет низкий уровень (0), то транзистор закрыт и Vout имеет уровень
земли (0). Если Vin высокий (1), транзистор открыт и Vout имеет +5V (1).

    -----------		-----+------
    Vin | Vout              Vin  | Vout   = Buffer
    ----+------		-----+------
    0V  | 0V                 0   |  0
    +5V | +5V                1   |  1
    -----------		-------------

А для NMOS - только через каскад инверторов:

  Недостатки NMOS технологии

  •  Когда транзистор(ы) открыт, то протекает ток от питания к земле.
     (Большое энергопотребление).

  •  В зависимости от того сколько и каких транзисторов открыто схема
     потребляет разное количество электричества.
     (Нестабильность энергопотребления - влияет на характеристики)

Имейте в виду что схемы нарисованы биполярными транзисторами,
а на самом деле они планарные.

  AND

[Идея - невозможна в NMOS]

    -------------------
    A  B  | NAND  AND
    ------+------------
    0  0  |  1     0
    0  1  |  1     0
    1  0  |  1     0
    1  1  |  0     1
    -------------------

[NMOS]

Пример моделирования NMOS AND2 на Verilog:

    module	nmos_and2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wand	ipull;
        wire	x;
        wand	pull;

        assign ipull = pwr;	// NAND
        nmos(ipull, x, a);
        nmos(x,  gnd, b);

        assign pull = pwr;	// NOT
        nmos(pull, gnd, ipull);
        assign out = pull;
    endmodule

Трехвходовый AND делается по аналогии с 3х входовым NAND.

  OR

[Идея -  невозможна в NMOS]

    -----------------
    A  B  | NOR  OR
    ------+----------
    0  0  |  1   0
    0  1  |  0   1
    1  0  |  0   1
    1  1  |  0   1
    -----------------

[NMOS]

Пример моделирования NMOS OR2 на Verilog:

    module	nmos_or2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wand	ipull;
        wand 	pull;

        assign ipull = pwr;	// NOR
        nmos(ipull, gnd, a);
        nmos(ipull, gnd, b);

        assign pull = pwr;
        nmos(pull, gnd, ipull); // NOT
        assign out = pull;
    endmodule

  XNOR

[XNOR HMOS]:

Имейте в виду - этот элемент не усиливает.
Усиливать будеть XOR - если после этого элемента еще поставить NOT.

Что бы получить усилинный XNOR - надо поставить 2 инвертора подряд на выход

    -----------
    A B | XNOR
    ----+------
    0 0 | 1
    0 1 | 0
    1 0 | 0
    1 1 | 1
    -----------

Пример моделирования NMOS XNOR2 на Verilog:

    module	nmos_xnor2(out,a,b);
        output	out;
        input	a,b;
        wand	pull;

        supply1	pwr;
        assign pull = pwr;
        nmos(pull, b, a);
        nmos(pull, a, b);
        assign out = pull;
    endmodule

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


4.4.2. ЭЛЕКТРИЧЕСКИЕ ОСНОВЫ (CMOS)

  CMOS технология

    Недостатки NMOS технологии привели к созданию CMOS технологии.
CMOS - (Complimentary Metal-Oxide-Semiconductor).
Основная идея CMOS: мы не хотим чтобы ток протекал от питания к земле в
момент работы, поэтому мы используем пару транзисторов (один n-типа,
другой p-типа, один из них соединяет выход с питанием, другой с землей.
Они дополняют друг друга (complimentary). В результате ток течет от
питания к земле в элементе только в момент переключения, в остальное время
энергопотребление значительно меньше.

Идея CMOS:

Сравнение мощности рассеяния CMOS и TTL в зависимости от частоты:

  NOT

Идея работы как NOT на NMOS технологии:
Если Vin имеет высокий уровень, то T1 открыт, а T2 закрыт,
как результат Vout cоединен с землей (0).
Если же Vin низкий то T1 закрыт, а T2 открыт, Vout соединен с
питанием (1).

    -------------		----------
    Vin  | Vout             Vin | Vout  = NOT
    -----+-------           ----+-----
    0 V  | +5V              0   | 1
    +5V  | 0V               1   | 0
    -----+-------           ----+-----

Форма спада на выходе CMOS:

Форма фронта на выходе CMOS:

Зависимость от напряжения питания:

Пример аналогового электрического моделирования CНMOS инвертора:

SPICE:
---------------------------------------------------------------

* Oscilloscope(s)
.PROBE V(14, 0)
R_o_scope_0_0 14 0 1Tohm
.PROBE V(15, 0)
R_o_scope_0_1 15 0 1Tohm

* Function Generator(s)
V_fg_plus 14 0 DC 0V AC 3V
+PULSE(-3V 3V 0 100ns 100ns 50ms 100ms)

* Battery(s)
V1 12 0 DC 5

* 3-Terminal Depletion N-MOSFET(s)
M_N_DM_Q1 15 14 0 0 NMDideal

* 3-Terminal Depletion P-MOSFET(s)
M_P_DM_Q2 15 14 12 12 PMDideal

* Misc

.MODEL NMDideal NMOS(VTO=0 KP=20u LAMBDA=0 PHI=600m GAMMA=0 Rd=0 Rs=0
+IS=10f Cgbo=0 Cgdo=0 Cgso=0 Cbd=0 Cbs=0 PB=800m RSH=0 CJ=0 MJ=500m CJSW=0
+MJSW=500m JS=0 TOX=100n NSUB=0 NSS=0 TPG=1 LD=0 U0=600 KF=0 AF=1 FC=500m
+TNOM=27)

.MODEL PMDideal PMOS(VTO=0 KP=20u LAMBDA=0 PHI=600m GAMMA=0 Rd=0 Rs=0
+IS=10f Cgbo=0 Cgdo=0 Cgso=0 Cbd=0 Cbs=0 PB=800m RSH=0 CJ=0 MJ=500m CJSW=0
+MJSW=500m JS=0 TOX=100n NSUB=0 NSS=0 TPG=1 LD=0 U0=600 KF=0 AF=1 FC=500m
+TNOM=27)

.END

---------------------------------------------------------------
Вид на осциллографе:

Пример моделирования CMOS NOT на Verilog:

    module	cmos_not(out,in);
        output	out;
        input	in;

        supply1	pwr;
        supply0	gnd;

        assign out = 1'bZ;
        pmos(out,pwr,in);
        nmos(out,gnd,in);
    endmodule

  NAND

Идея CMOS NAND та же что и в NMOS NAND.

Если V1 и V2 высокие, то Vout соединен с землей (0)
(T1L и T2L открыты, T1H и T2H закрыты).

В другом случае как минимум один из T1L и T2L закрыт,
и один из T1H и T2H открыт, Vout соединен с питанием (1).

    --------------		-------------
    V1  V2 | Vout           V1  V2 | Vout	= NAND
    -------+------		-------+-----
    0V  0V | +5V		0   0  |  1
    0V +5V | +5V            0   1  |  1
    +5V 0V | +5V            1   0  |  1
    +5V +5V| 0V             1   1  |  0
    --------------		-------------

Схема для электрического моделирования CMOS NAND2:

Результаты электрического моделирования:

Пример моделирования CMOS NAND2 на Verilog:

    module	cmos_nand2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wire	x;

        assign out = 1'bZ;
        pmos(out,pwr,a);
        pmos(out,pwr,b);

        nmos(x,gnd,b);
        nmos(out,x,a);
    endmodule

  NOR

Идея CMOS NOR та же что и в NMOS NOR и CMOS NAND.
Любой из T1L и T2L делает 0 на Vout.
Оба вместе T1H и T2H делают 1 на Vout.

    --------------		-------------
    V1  V2  | Vout          V1  V2 | Vout = NOR
    --------+-----		-------+-----
    0V   0V | +5V		 0  0  | 1
    0V  +5V | 0V             0  1  | 0
    +5V  0V | 0V             1  0  | 0
    +5V +5V | 0V             1  1  | 0
    --------------          -------------

Пример моделирования CMOS NOR2 на Verilog:

    module	cmos_nor2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wire	x;

        assign out = 1'bZ;
        pmos(x,pwr,a);
        pmos(out,x,b);

        nmos(out,gnd,a);
        nmos(out,gnd,b);
    endmodule

  Buffer

Из за электрических свойств транзисторов [не будем углубляться]
CMOS буффер имеет специфику и реализуется не как CMOS инвертер,
а как 2 инвертора идущих последовательно.

Пример моделирования СMOS буфера на транзисторном уровне на Verilog:

    module	cmos_buf(out,in);
        output	out;
        input	in;

        supply1	pwr;
        supply0	gnd;
        wire	x,y;

        assign x = 1'bZ;
        pmos(x, pwr, in);
        nmos(x, gnd, in);

        assign out = 1'bZ;
        pmos(out, pwr, x);
        nmos(out, gnd, x);
    endmodule

  Tristate

NOT с tristate

CMOS логика позволяет делять тристабильный элемент (Tristate),
т.е. элемент на выходе  которого может быть высокоимпедансное состояние
(состояние с высоким сопротивлением когда ток не течет через элемент).

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

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

    --------------
    EN  A  |  OUT   = Tristate
    -------+------
    0   0  |  Z
    0   1  |  Z
    1   0  |  0
    1   1  |  1
    --------------

Пример моделирования СMOS тристабильного элемента на транзисторном уровне на Verilog:

    module	cmos_tristate(out,a,en);
        output	out;
        input	a,en;

        supply1	pwr;
        supply0	gnd;
        wire	eni, up, down;

        cmos_not   EN_NOT(eni,en);
        cmos_nand2 UP_CHAIN(up, en, a);
        cmos_nor2  DOWN_CHAIN(down, eni, a);

        assign out = 1'bZ;
        pmos(out, pwr, up);
        nmos(out, gnd, down);
    endmodule

  AND

Пример моделирования CMOS AND2 на Verilog:

    module	cmos_and2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wire	x,iin;

        assign iin = 1'bZ;
        pmos(iin,pwr,a);
        pmos(iin,pwr,b);

        nmos(x,gnd,b);
        nmos(iin,x,a);

        assign out = 1'bZ;
        pmos(out, pwr, iin);
        nmos(out, gnd, iin);
    endmodule

  OR

Пример моделирования CMOS OR2 на Verilog:

    module	cmos_or2(out,a,b);
        output	out;
        input	a,b;

        supply1	pwr;
        supply0	gnd;
        wire	x, iin;

        assign iin = 1'bZ;
        pmos(x,pwr,a);
        pmos(iin,x,b);

        nmos(iin,gnd,a);
        nmos(iin,gnd,b);

        assign	out = 1'bZ;
        pmos(out, pwr, iin);
        nmos(out, gnd, iin);
    endmodule

  XOR

Реализация XOR на CMOS:

Каноническая имплементация XOR на CMOS занимает очень
много транзисторов (12) (на схеме еще не показаны 4 транзистора,
которые нужны для инвертирования A и B.

Есть более хитрые методы реализации XOR используя pass-through logic.

Реализация XOR на PTL:

Идея:
                   _     _
    XOR(X,Y) = XY + YX

    ----------
    X Y | XOR
    ----+-----
    0 0 | 0
    0 1 | 1
    1 0 | 1
    1 1 | 0
    ----------

Если Х = 0, то XOR = Y
Если X = 1, то XOR = Y#

Пример моделирования CMOS XOR2 на Verilog:

    module	cmos_xor2(out,a, b);
        output	out;
        input	a,b;
        wire	ia, ib;
        wor	x;

        cmos_not  INVERT_A(ia,a);
        cmos_not  INVERT_B(ib,a);

        assign x = 1'bZ;

        pmos(x, a, b);
        nmos(x, a, ib);

        pmos(x, ia, ib);
        nmos(x, ia, b);

        assign out = x;
    endmodule

Каноническая CMOS реализация XOR с 4мя входами.

  XNOR

                         _ _
    XOR(X,Y) = X*Y + X*Y

    -----------
    X Y | XNOR
    ----+------
    0 0 | 1
    0 1 | 0
    1 0 | 0
    1 1 | 1
    -----------

Если Х = 0, то XNOR = Y#
Если X = 1, то XNOR = Y

XNOR реализуется аналогично XOR в 8ми транзисторную структуру.

(В 12 - если канонически)


4.4.2.1. ТОПОЛОГИЯ CMOS

Пример топологии для CMOS инвертора (пара MOSFET транзисторов):

-----------------------------------------------------------------------------

                                   Vin
                  |  |
                   +--------------+  +-------------+
                   |  +-------------------------+  |
                   |  |                         |  |
    +----------|  |-----------+             |  |
    |    n     |  |   n       |             |  |
    |   +------|  |--------+  |    +--------|  |-----+
    |   |    p |  | p      |  |    |  n     |  |   n |
---------------+   |  |  +--+  |  |    |  +--+  |  | +----------------
GND	       |   |  |  |  |  |  |    |  |  |  |  | |           Vcc
---------------+   |  |  |  |  |  |    |  |  |  |  | +----------------
    |   |	   |  |  |  |  |  |    |  |  |  |  |     |
    |   +------|  |--|  |--+  |    +--|  |--|  |-----+
    +----------|  |--|  |-----+       |  |  +--+
           +--+  |  |             |  |
             |  +-------------+  |
             +--------+  +-------+
                      |  |
                       Vout

n - зона электронной проводимости
р - зона дырочной проводимости
подложка имеет дырочную проводимость.
-----------------------------------------------------------------------------

Разрез вдоль линии GND-Vcc:

----------------------------------------------------------------------------

                 +-----+                         +-----+
                 | Vin |                         | Vin |
 --------------+ +-----+ +----+           +----+ +-----+  +-----------
      Vcc      | |oxide| |Vout|           |Vout| |oxide|  |    GND
 ------+----+------+--+--------+--+------+--------+--+------+------
       |    |  p   |  |  p     |  |      |   n    |  |  n   |
       |    +------+  +--------+  |      +--------+  +------+
       |         n-карман         |
       +--------------------------+
                               p-подложка

        P-MOSFET			N-MOSFET

----------------------------------------------------------------------------

    когда Vin=1 есть ток			Когда Vin=0 он уводит
    электроны открывают зону		элетроны из зоны n-проводимости
    p-проводимости и ток течет		дырки текут от Vcc к Vout
    от GND к Vout.				(a электроны наоборот).

  NOT

  NOR

  NAND

  Правила топологии


4.4.2.2. СЛОЖНАЯ ЛОГИКА НА CMOS

Схемы типа ИЛИ-И, и И-ИЛИ оптимизируются на уровне CMOS транзисторов:

  AOI

AOI (And-Or Inverted)

Таблица истинности для AOI:
    -------------------
    D C B A  CD AB  AOI
    -------------------
    0 0 0 0  0  0   1
    0 0 0 1  0  0   1
    0 0 1 0  0  0   1
    0 0 1 1  0  1   0
    0 1 0 0  0  0   1
    0 1 0 1  0  0   1
    0 1 1 0  0  0   1
    0 1 1 1  0  1   0
    1 0 0 0  0  0   1
    1 0 0 1  0  0   1
    1 0 1 0  0  0   1
    1 0 1 1  0  1   0
    1 1 0 0  1  0   0
    1 1 0 1  1  0   0
    1 1 1 0  1  0   0
    1 1 1 1  1  1   0
    -------------------

Пример моделирования CMOS AOI4 на Verilog:

    module	cmos_aoi4(out,a,b,c,d);
        output	out;
        input	a,b,c,d;

        supply1	pwr;
        supply0	gnd;
        wire	x,y,z;

        pmos(x, pwr, a);
        pmos(x, pwr, b);

        nmos(y, gnd, a);
        nmos(z, gnd, c);

        assign out = 1'bZ;

        pmos(out, x, c);
        pmos(out, x, d);

        nmos(out, y, b);
        nmos(out, z, d);
    endmodule

  OAI (Or-And-Inverted)

Таблица истинности для OAI:
    --------------------
    D C B A  C+D A+B OAI
    --------------------
    0 0 0 0  0   0   1
    0 0 0 1  0   1   1
    0 0 1 0  0   1   1
    0 0 1 1  0   1   1
    0 1 0 0  1   0   1
    0 1 0 1  1   1   0
    0 1 1 0  1   1   0
    0 1 1 1  1   1   0
    1 0 0 0  1   0   1
    1 0 0 1  1   1   0
    1 0 1 0  1   1   0
    1 0 1 1  1   1   0
    1 1 0 0  1   0   1
    1 1 0 1  1   1   0
    1 1 1 0  1   1   0
    1 1 1 1  1   1   0
    --------------------

Пример моделирования CMOS AOI4 на Verilog:

    module	cmos_oai4(out,a,b,c,d);
        output	out;
        input	a,b,c,d;

        supply1	pwr;
        supply0	gnd;
        wire	x,y,z;

        pmos(y, pwr, a);
        pmos(z, pwr, c);

        nmos(x, gnd, a);
        nmos(x, gnd, b);

        assign out = 1'bZ;

        pmos(out, y, b);
        pmos(out, z, d);

        nmos(out, x, c);
        nmos(out, x, d);
    endmodule

  Более сложные функции

Оптимизация сложной функции на уровне транзисторов CMOS:

Как правило ручная топология CMOS имеет вид:

    +-------------------------------------------------+
    |						  |  Vcc BUS
    +-------------------------------------------------+
      +-------+  +--------+  +-------+  +-------+
      |   P   |  |   P    |  |   P   |  |   P   |
      +-------+  +--------+  +-------+  +-------+
    +-------------------------------------------------+
    |						  | Output
    +-------------------------------------------------+
      +-------+  +--------+  +-------+  +-------+
      |   N   |  |   N    |  |   N   |  |   N   |
      +-------+  +--------+  +-------+  +-------+
    +-------------------------------------------------+
    |						  | GND
    +-------------------------------------------------+

Пускают шины Vcc и GND. Между ними P и N транзисторы. В самой середине
межсоединения повышающего/понижающего каскадов.

Практически все сложные CMOS структуры имееют такую форму.
Разница в соединениях транзисторов и input/output сигналов.

Поэтому в микросхемах все расположено в "нитках".

Оптимизация топологии (CMOS в линеечку)


4.4.2.3. ЗАПИРАЮЩИЙ ЭЛЕМЕНТ

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

Таблица показана только в одну сторону (от IN к OUT), реально же
распространение в две стороны.

Спрашивается: почему надо 2 MOSFET, а не один?
Все дело в полярности MOSFET. Один будет пропускать только в одну сторону.

Топология запирающего элемента:


4.4.2.4. BiCMOS ТЕХНОЛОГИЯ

На определенном этапе развития была использованна BiCMOS технология
являющаяся смесью CMOS и биполярных транзисторов.
Дело в том что биполярные транзисторы в определенных условиях работают
быстрее.
Потом от BiCMOS отказались т.к. вместе со степенью интеграции уменьшилось
напряжение питания а на p-n переходе падение достаточно большое.

BiCMOS элементы были по размерам больше чем чисто CMOS элементы,
но работали немного быстрее.

Сравнение быстродействия CMOS и BiCMOS

  NOT

Схема BiCMOS инвертора:

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

Схема BiCMOS инвертора (оптимизированный):

Сигнал от BiCMOS инвертора:

Сигнал от CMOS инвертора:

Характеристика BiCMOS инвертора:

Сборка BiCMOS инвертора из CMOS и BJT:

Срез BiCMOS инвертора:

  NAND

Схема BiCMOS элемента NAND (оптимизированный):

Сборка BiCMOS NAND из CMOS и BJT:

Так же собираются и другие BiCMOS элементы:
Сначала CMOS который делает логику, затем BJT на выходе.

Оптимизация BiCMOS по скорости делается дублирующей CMOS цепью
цель которой не давать BJT работать.


4.4.2.5. ДИНАМИЧЕСКАЯ CMOS ЛОГИКА

  Динамический CMOS

В 80-х годах очень активно использовалась динамическая CMOS логика.

Например элемент памяти можно было реализовать на 3х транзисторах:

Методика работы такая: когда CLK1 активен устанавливается состояние,
затем CLK1 закрывается.
Тем не менее у вентиля есть паразитная емкость и пока заряд не стечет
а у транзисторов высокий импеданс схема будет работать.

Время стока заряда зависит от температуры и проектной нормы.
Для 1.5mkm это в интервале от 1 (при очень малой температуре) до 10^(-6)
секунд.

386, большая часть 486 процессоров были динамическими (как следствие
могли работать только в ограниченном диапазоне тактовых частот).
С уменьшением проектной нормы заряд стал уходить гораздо быстрее,
и от динамических структур стали отказыватся, хотя в свое время они позволяли
экономить много места на кристале.

Общий вид динамической структуры:

Динамический NAND:

Динамический NOR:

Для увеличения скорости применяются более сложные варианты логики
на базе CMOS:

  CVSL

(Cascade Voltage Switch Logic)

Идея: выдает две функции прямую и обратную - быстро переключается
между состояниями.

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

Cтатический CVSL:

Динамический CVSL:
(при С = 0 заряжается, при С =  1 вычисляет).

  DCVSL

XOR/XNOR:

  Логика на переключателях

AND:

AND/NAND:

OR/NOR:

XOR/XNOR:

  Динамическая логика

Динамическая логика имеет по крайней мере один pre-charge транзистор.
Работает в две фазы - pre-charge и evaluation.

  Domino

Логика Domino.
В начале транзистор на питание открыт (CLK#), происходит презарядка.
В зоне перед инвертером накапливается заряд.
После этого транзистор закрывается и заряд либо остается либо стекает
Через NMOS блок (транзистор на землю открыт (CLK)).
При этом сигналы на NMOS блок должны быть поданы то сигнала CLK.

Получается - места на кристалле занимает меньше чем CMOS, но чуть больше
чем NMOS, при этом имеет энергопотребление типа CMOS.

Такие структуры следуют одна за другой (домино).
Последний каскад содержит инвертор.

AND на Domino логике:

OR на Domino логике:

  NP-Домино

NP-CMOS:

  Pseudo-NMOS

NAND:

NOR:

  C2MOS

Два каскада - повышающий и понижающий. А выход каскада зависит от сигнала CLOCK.
Опять таки снижается энергопотребление - т.к. нет переходных процессов.

  TSPC

TSPC (Time Single Phase Logic)
TSPC - дальнейшее развитие NORA (NO RAce logic) [которая развитие N-P домино].

AND на TSPC:

OR на TSPC:

  Почему не используется?

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


4.4.2.6. БОРЬБА ЗА ПОНИЖЕННОЕ ЭНЕРГОПОТРЕБЛЕНИЕ В IDLE РЕЖИМЕ

THIS SECTION IS UNDER CONSTRUCTION

  BGCMOS

  MTCMOS


4.4.2.7. PTL (PASS-TRANSISTOR LOGIC)

THIS SECTION IS UNDER CONSTRUCTION

  XOR

  XNOR

  OR

  AND

  Импликация

X1 - > X2

соответсвенно импликация от X2 -> X1 просто меняем местами входы.

  Запрет

Запрет по x2:

X1 < - X2


4.4.2.8. РЕАЛИЗАЦИЯ ЛОГИЧЕСКИХ ФУНКЦИЙ

Для полупроводниковых технологий NOT, NOR и NAND - базовые логические элементы
которые могут быть реализованны электрически.
XNOR, в некоторых случаях XOR тоже могут быть соптимизированны на уровне
транзисторной технологии. Собственно импликации и запреты тоже можно соптимизировать.

Другие элементы реализовываются уже комбинационно-логичским путем исходя из них:

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

  IMP

Рассмотрим импликацию A->B:

    ----------
    A B | A->B
    ----+-----
    0 0 | 1
    0 1 | 1
    1 0 | 0
    1 1 | 1
    ----------
               _
Заметим что A->B = A + B

    --------------------
    A A# B | A#+B  A->B
    -------+------------
    0 1  0 |  1     1
    0 1  1 |  1     1
    1 0  0 |  0     0
    1 1  1 |  1     1
    --------------------

таким образом получаем импликация A->B - это:

или просто:

  Запрет

Рассмотрим запрет по А  (B <- A):

    ----------
    A B | B<-A
    ----+-----
    0 0 | 0
    0 1 | 1
    1 0 | 0
    1 1 | 0
    ----------
                _
Заметим что  B<-A = A * B

    --------------------
    A A# B | A#*B  B<-A
    -------+------------
    0 1  0 |  0     0
    0 1  1 |  1     1
    1 0  0 |  0     0
    1 1  1 |  0     0
    --------------------

таким образом:

или просто:

  NOT

  NAND

NAND3:

NAND4:

  NOR

NOR3:

NOR4:

  AND

Реализация на NAND:

    x AND y = NOT (x NAND y)

Реализация на NOR:

    x AND y = (NOT x) NOR (NOT y)

AND3:

AND4:

  OR

Реализация на NAND:

    x OR y = (NOT x) NAND (NOT y)

Реализация на NOR:

    x OR y = NOT (x NOR y)

OR3:

OR4:

  Buffer

Реализация на NOT (CMOS-only):

  XOR/XNOR

A (+) B = A#*B + A*B#

A (+) B = A#*B + A*B# = A*A# + A#*B + A*B# + B*B# =
    = A*(A# + B#) + B*(A#+B#) =
    = A*(A#*B#)   + B*(A#*B#) =
    = (A + B) * (A*B)#

XOR на NAND:

Помним что самом деле XOR может быть оптимизирован на уровне транзисторов:
(Пример для CMOS)

Реализация выглядит как 3 инвертора и один электронный переключатель.

XOR с двумя входами на CMOS:

XOR3:

XOR4:

XOR c 4 входами на CMOS:

  *

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


4.4.3. ЭВОЛЮЦИЯ

  Эволюция

Проектная норма все уменьшается:

Начинает сильно играть роль скорость межсоединений.

Увеличиваются индуктивные наводки между элементами:

Увеличивается число слоев метализации
CMOS 7S:

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

Уменьшим напряжение питания вдвое.
Частоту придется тоже уменьшить вдвое.
Но устройство будет потреблять вчетверо меньше.

  Лимитирующие факторы

------------------------------------------------------------------------------
Максимальная 	100x100 нм	Статистические флуктуации легирования подложки
величина			Разрешение фоторезиста
элемента			Космические лучи, радиактивность
                Конечная ширина p-n перехода
------------------------------------------------------------------------------
Мин Толщина  	50 A		Туннельные токи из затвора в канал
подзатворного
изолятора
------------------------------------------------------------------------------
Мин Напряжение	0.025 В		Тепловой потенциал (kT/q)
питания
------------------------------------------------------------------------------
Мин Плотность	10^-6 A/см^2	Дискретность заряда электрона
тока				Флуктуации встроенного заряда
------------------------------------------------------------------------------
Предельное    	0.03 нс		Скорость света
быстродействие
------------------------------------------------------------------------------
Мин     	10^-12 Вт/элемент  Шумы,
мощность	при F = 1kHz	Диэлектрическая составляющая
------------------------------------------------------------------------------


4.4.3.1. РАЗГОН CMOS

Интерестно - максимальную скорость CMOS достигает при ~-150 'C.
Охлаждая процессор жидким азотом - можем поднять частоту раза в 3.

Пример Pentium 4 3.6GHz разогнан до 6GHz.
Процессор охлаждают жидким азотом.

Плотность энергии:

В настоящее время любят использовать CMOS с разным напряжением питания
(это позволяет уменьшить энергопотребление).


4.4.3.2. СОВРЕМЕННЫЕ ТЕХНОЛОГИИ

  SOI

SOI (Silicon on Insulator)

Раньше тактовые частоты были маленькие, напряжения большие и транзисторы
травили прямо на кремнеевой подложке.
Но с ростом частот и уменьшении размера ячейки все больше стал играть
роль эффект паразитной емкости кремниевой подложки.
Что бы избавится от этого эффекта под транзисторной структурой стали
распологать слой SiO2. (Silicon on Insulator = SOI).

Original (раньше):

SOI (теперь):

  Растянутый кремний

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

  3D структуры

V-образный транзистор

3D двухсторонний транзистор:
(Один затвор открывает 2 транзистора в 3D структуре)

Двухзатворный транзистор:

Реальные 3D структуры:
(нижний слой (на подложке) логика, в объеме память, сверху optical
interconnect. [реальные прототипы уже есть].

Эволюция
(от планарного транзистора, через SOI к двухзатворному и
в перспективе к реальной 3D структуре:

  Нанотрубки

Углеродные нанотрубки как канал транзистора

Плотность тока в несколько десятков раз выше чем у кремневых
транзисторов.
Размер транзистора получается в несколько раз меньше.
Кроме того меньше рабочее напряжение затвора.

  Охлаждение on-chip

AMD получил патент на использование холодильника Пельтье
(TEC, thermoelectric cooler) внутри кристала.
На левой картике мы видим три транзистора в верхнем слое,
под ними находятся холодильники Пельтье, питание к ним подводится с боков
(+ и -).

Эффект Пельтье - пластины из 2х металов, полупроводник внутри при прохождении
тока идет переход тепла из одной пластины в другую.
[Образующее Электрическое поле пропорционально температурному градиенту].

Реальные устройства содержат цепочку элементов Пельтье.
(На AMD правом рисунке (см выше) видно устройство).


4.4.4.1. ЗАЩИТА ВХОДОВ И ВЫХОДОВ

Транзисторы внутри микросхемы очень чуствительны к статическому электричеству
Напряжение около 50V убивает их навсегда.
Что бы этого не было применяют диодную защиту.
Которая уводит заряд в случае лишнего напряжения на источник (GND и/или Vcc)

Это пример защиты и входного и выходного каскадов.
Лишний заряд уходит через диоды.
А внутрь идет через CMOS развязку.


4.4.4.2. ОТКРЫТЫЕ СТОКИ И ШИНЫ

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

Идея шины и открытых стоков:

Выходы с открытым стоком помечают как правило схемотехническим знаком:

    /\
       /  \
       \  /
        \/
       ----

Пример CMOS открытого стока:

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

Модель устройства с открытым стоком.
Имеет два входа - один это сигнал который выставлять на шину,
другой - разрешение выставления на шину:

    module	cmos_opendrain(out,in,en);
        output	out;
        input	in;
        input	en;
        wire	iin;
        wire	x;

        cmos_not CMOS_NOT_1(iin, in);

        supply0	gnd;

        assign out = 1'bZ;
        nmos(x,   gnd, en);
        nmos(out, x, iin);
    endmodule

Модель шины:

    module	bus_test(a,b,ena, enb);
        input	a,b,ena,enb;
        wand	bus;
        supply1	pwr;

        assign	bus = pwr;
        cmos_opendrain DEVICE0(bus,a, ena);
        cmos_opendrain DEVICE1(bus,b, enb);
    endmodule

Результаты моделирования:
Видно, что когда никто не выставляется на шину то ее значение 1.
(вот почему если читать зону за пределами физической оперативной памяти
мы получаем одни FFh).
Если кто-то один выставляется - то результатты соответсвуют данным.
Если выставляются сразу оба - то побеждает тот кто выставляет 0.
(Эта особенность используется для арбитража шины).

  Монтажная логика

Собственно говоря шина основанная на открытых стоках выполняет логическую функцию
AND. Если у кого-то 0 - то на шине будет тоже 0.
Поэтому ее иногда еще называют монтажной логикой.
(Это верно для CMOS и TTL)

Для ECL наоборот - открытый сток означает функцию OR


4.4.4.3. СОВРЕМЕННЫЕ ЭЛЕКТРИЧЕСКИЕ ШИНЫ

Проблемы связанные с шинами (такие же с разводкой выводов chipов):

    - паразитные емкости и индуктивности
    - отражения в линиях передачи

  GTL

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

THIS SECTION IS UNDER CONSTRUCTION

GTL+ шина начала применятся на x86 начиная c Pentium Pro.

Принцип работы GTL:

Основная идея - использование моста для более быстрого получения сигнала
в приемнике.

Схема шины GTL+

Уровни сигналов GTL и GTL+

  HSTL

Принцип работы HSTL:

использование операционного усилителя на входе для более быстрого получения сигнала.

  LVDF

Схема LVDF:

Использование дифференциальной передачи.

  Пример современных шин

Процессорная шина:

Хабовая шина:


4.4.5. ЭМИТЕРНО-СВЯЗАННАЯ ЛОГИКА

Идея ЭСЛ это противостояние двух одинаковых транзисторов, связааных
эммитерами на один из которых подают входной сигнал,
а на другой эталонный (+4.0V) который ниже чем 1, но выше чем 0.
В результате такая схема работает гораздо быстрее чем NMOS или CMOS
(потому что разница между уровнями мала и скорость изменения напряжения
получается гораздо быстрее [работу делают два транзистора]).
Все классические суперкомпьютеры (типа Cray X-MP) делают на ЭСЛ элементной
базе.
Недостатки ЭСЛ:
    Необходимо двойное питание
    Очень большое энергопотребление

Пример инвертора на ЭСЛ:

OUT1 - инверсный выход (NOT)
OUT2 - прямой выход    (Buffer)
Обратим внимание, что это сразу и инвертер и буфeр.

ЭСЛ дает сразу и прямой и инверсный выходы.
Идеи для реализации NOR, NAND такие же как в NMOS и CMOS.
(Но при этом автоматически получается и OR, AND):

  NAND/AND

  NOR/OR

Наращивание числа входов так же как в NMOS/CMOS.


4.4.5.1. ТРИГГЕР ШМИТТА

Это инвертор с триггером Шмитта:

Характеристика триггера Шмитта:

    Vout ^
     |    +--<--+--
     |    |     |
     |    |     |
     |    |     |
     | ---+-->--+
     +--------------->
                    Vin

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

Это реализация триггера Шмитта в CMOS:

Реализация триггера Шмитта н BJT:

Триггеры Шмитта обозначаются знаком:

Пример реализации тригера Шмитта на операционном усилителе:

Пример моделирования электрического поведения инвертора с триггером Шмитта:

Собственно могут быть и другие элементы Шмидта кроме инвертора,
например NAND:


4.4.5.2. ЭЛЕМЕНТ ЗАДЕРЖКИ

Элемент задержки задерживает прохождения сигнала на некоторое время.
Работа элемента основана на RC-цепочке и паре триггеров Шмита, которые
подавляют биения:

Программа на VHDL эмулирующая элемент задержки на 10 ns.

    library IEEE;
    use IEEE.std_logic_1164.all;

    entity delay is
            port (
                A: in STD_LOGIC;
                B: out STD_LOGIC);
    end delay;

    architecture delay_arch of delay is
    begin
            B <= A after 10 ns;
    end delay_arch;

Результат симуляции элемента задержки:


4.4.6. I2L ЛОГИКА (ИНЖЕКТОРНАЯ ЛОГИКА)

I2L (Integrate Injector Logic)

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

Идея в основе I2L элемента.

пусть  входное напряжение равен 1, тогда ток инжектора VT1 не уходит на вход
а насыщает транзистор VT2, поэтому выходы выход 1 и выход 2 имеют низкий уровень
и наоборот: если входное равно 0, ток с инжектора уходит на вход, транзистор
VT2 не открывается - как результат высокое состояние на выходе (т.к. на следующих
входах тоже инжекторы.

Пример I2L инвертора:

Пример реализации AND и NOR на I2L:

Основная идея - это соединение выходов транзисторов - за счет этого мы
имеем функцию монтажного ИЛИ. Все остальное это уже комбинации между монтажным
ИЛИ и НЕ.

    --------------------------------------------
                    NOR	AND
    X1	X2	T1	T2	T1+T2   T3
    --------------------------------------------
    0	0	1	1	1       0
    0	1	1	0	1       0
    1	0	0	1	1       0
    1	1	0	0	0       1
    --------------------------------------------

                  __   __    _______
    NOR(x1,x2)  = x1 + x2  = x1 * x2
                  __   __    _______
    NAND(X1,X2) = x1 * x2  = x1 + x2

соответсвенно:
    OR    = NOT(NOR(X1,X2))
    NAND  = NOT(AND(X1,X2))

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


4.4.7. TTL ЛОГИКА

TTL - Transistor Transistor Logic
Раньше была очень широко распространена (особенно дискретные компоненты).

  NOT

D1, Q1 - Диодная NOT логика и защита входа.
Q2     - расщепитель фазы
Q3,Q4  - выходной каскад

    Input	Q1   Q2   Q3  Q4
    Low          off  on  off
    High	     on   off on

  NAND

    A     B	   Q1   Q2   Q3
    Low  Low   off	on   on
    Low  High  off  on   on
    High Low   off  on   on
    High High  on   off  off

  NOR

  AND

  OR


4.4.8. DCFL

DCFL (Direct Coupled FET logic) применяется в устройствах на основе
арсенида галлия (GaAs).

Особенность DCFL в том, что элементы NAND в ней не реализуют.

  NOT

  NOR


4.5. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ НА HDL ЯЗЫКАХ

В этой секции мы расмотрим модели логических элементов на языках
для разработки электронной аппаратуры:

  •  VHDL (VLSI Hardware Description Language)

  •  Verilog

Упор будет делатся на VHDL, т.к. он для начинающих более понятен.
Можно сравнить:
    VHDL	- Pascal
    Verilog	- C

  NOT

           --------
        X | NOT X
               ---+----
        0 | 1
            1 | 0
               --------

Программа на VHDL:

    entity NOT is
        port (
            A : in bit;
            B : out bit);
    end NOT;

    architecture RTL of NOT is
    begin
        D <= not A after 2 ns;
    end RTL;

Программа на Verilog:

    `timescale 1 ns / 10 ns
    module Not1 (A, B) ;
    input A ;
    output B ;

      assign #5 B = ~(A);

    endmodule

Результатирующая временная диаграмма (для VHDL):

  AND

           ---------------
        X1  X2  | AND	таблица истинности
           ---------+-----
        0   0   | 0
        0   1   | 0
            1   0   | 0
        1   1   | 1
           ---------------

Программа на VHDL:

    entity AND2 is
        port (
            X1,X2: in bit;
            Y : out bit);
    end AND2;

    architecture RTL of AND2 is
    begin
        Y <= X1 and X2 after 5 ns;
    end RTL;

Программа на Verilog:

    `timescale 1 ns / 10 ns
    module AND2M (A, B, C) ;
    input A ;
    input B ;
    output C ;

    assign #5 C = A & B;
    endmodule

Результатирующая временная диаграмма (для VHDL):

  OR

            --------------
        X1  X2	| OR
        --------+-----
        0   0	| 0
        0   1	| 1
        1   0	| 1
        1   1	| 1
               ---------------

    entity Or2 is
        port(
            A, B : in std_logic;
            D : out std_logic);
    end Or2;

    architecture Example of Or2 is
    begin
        D <= (A or B) after 2 ns;
    end Example;

Результатирующая временная диаграмма:

  NOR

               ---------------
        X1  X2	| NOR
        --------+-----
        0   0	| 1
        0   1	| 0
        1   0	| 0
        1   1	| 0
               ---------------

    entity Nor2 is
        port(
            A, B : in std_logic;
            D : out std_logic);
    end Nor2;

    architecture Example of Nor2 is
    begin
        D <= not (A or B) after 2 ns;
    end Example;

Результатирующая временная диаграмма:

  NAND

           ---------------
        X1  X2  | NAND
           ---------+-----
        0   0   | 1
        0   1   | 1
            1   0   | 1
        1   1   | 0
           ---------------

    entity Nand2 is
        port(
            A, B : in std_logic;
            D : out std_logic);
    end Nand2;

    architecture Example of Nand2 is
    begin
        D <= (A nand B) after 2 ns;
    end Example;

Результатирующая временная диаграмма:

  XOR

           ---------------
        X1  X2  | XOR
           ---------+-----
        0   0   | 0
        0   1   | 1
            1   0   | 1
        1   1   | 0
           ---------------

    entity Xor2 is
        port(
            A, B : in std_logic;
            D : out std_logic);
    end Xor2;

    architecture Example of Xor2 is
    begin
        D <= (A xor B) after 2 ns;
    end Example;

Результатирующая временная диаграмма:

  Tristate

           ---------------
        EN  A   | Tristate
           ---------+-----
        0   0   | Z	высокий импеданс, ток не течет
        0   1   | Z     высокий импеданс, ток не течет
            1   0   | 1
        1   1   | 0
           ---------------

    entity TRISTATE1 is
        port(
            A, E : in std_logic;
            D : out std_logic);
    end TRISTATE1;

    architecture Example of TRISTATE1 is
    begin

        D <= A WHEN (E='1') ELSE 'Z';
    end Example;

Результатирующая временная диаграмма:

Программа на Verilog:

    module TRISTATE1 (E,A,D);
        input	A,E;
        output  D;
        reg	D;

        always @(E or A) begin
            if (E)
                D = A;
            else
                D = 1'bz;
        end
    endmodule


4.5.1. СТОИМОСТЬ ЛОГИЧЕСКИХ ЭЛЕМЕНТОВ

В таблицы привидены примерные типовые параметры стоимости логических элементов:
(для CMOS):

    -------------------------------------------
    Элемент	  Задержка   Площадь  Транзисторов
    -------------------------------------------
    NOT	   1T	      <1S	2
    NAND2	   2T	      1S	4
    NOR2	   2T         1S        4
    NAND3	   3T	      1.5S	6
    NOR3	   3T	      1.5S	6
    Buffer     2T         1S        4
        AND2       >2T        2S        6
    OR2        >2T        2S        6
    XOR2       2T         3S        8
    XNOR2      2T         3S        8
    AOI4       >2T        3S        8
    OAI4       >2T        3S        8
    --------------------------------------------

Площадь меньше чем кол-во транзисторов потому что она оптимизированна.


4.5.2. ЗАДЕРЖКИ

При прохождении сигналов через логические элементы происходят задержки.

      Задержки
          /    \
 Транспортные Инерциальные

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

Через инвертор:

Через каскад 3 инвертора:

При моделирование логических устройств используются разные модели:
    - Без задержек 		(подходит примерно 10% моделям)

    - С задержками (инерционными, включают транспортные)
                (покрывает примерно 90% моделей)
         пример когда логическое моделирование не помогает
         предположим что у нас очень часто идут пики небольшого размера
         со скважностью более 50%. Инерционная модель их все отбросит
         а в реальности паразитные емкости будут заряжаться и в конце
         концов элемент сработает, а модель нет.

Фронт и спад имеют разные задержки

    - С задержками (моделируем на электрическом уровне)
                (покрывает практически все).

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


4.5.3. РАЗВЕТВЛЕНИЯ

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

Кроме того - чем fun-out больше тем медленнее логический элемент устанавливает
на выходе свое состояние.

Формулы для вычисления fun-out.
(Обратите внимания что для различного уровня сигнала fun-out может быть различный
и надо выбирать наименьший из них).


4.5.4. СИНХРОНИЗАЦИЯ

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

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

Clock skew
Сдвиг синхронизации по времени

Clock jitter
Разные периоды синхросигнала имеют разную продолжительность

Clock skew sources:

Задержки синхронизации в процессоре Alpha:

Что бы боротся с погрешностями синхронизации приходится добавлять дополнительное
время в течении которого сигналы стабильны - до и после синхронизации.
(В современных процессорах эта борьба отнимает до 20% времени такта)

Асинхронные сигналы типа RESET тоже надо синхронизировать для того что бы система
адекватно реагировала на них.


4.5.5. ПОМЕХИ И ПОТЕРИ

THIS SECTION IS UNDER CONSTRUCTION


4.5.6. СОПРЯЖЕНИЕ МЕЖДУ СОБОЙ РАЗЛИЧНЫХ ТЕХНОЛОГИЙ

THIS SECTION IS UNDER CONSTRUCTION

  TTL в CMOS

  TTL в ECL

  ECL в TTL

  CMOS в TTL

  CMOS в CMOS с другим питанием


4.6. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ НА ДИСКРЕТНЫХ КОМПОНЕНТАХ

У Кошки 4 ноги - ввод, вывод, земля и питание.

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

Серии дискретных компонентов TTL:

    US	RUS
    74	155
    74L	158	Low-power
    74H	131
    74S	531	Shotky
    74LS	533	Shotky low-power
    74ALS	1533	Advanced Shotky low-power
    74AS	1530	Advance shotky
    74F	1531	Fast

Серии дискретных компонентов CMOS:
    US
    4000/14000	original
    74C		CMOS
    74HC/74HCT	Fast CMOS
    74AC/74ACT	Advanced CMOS
    74ACH/74ACT	Advanced Fast
    74LVC		low-voltage max 5V
    74ALVC		Advanced low-voltage max 3.3V
    74LV		3.3V
    74AVC		max 2.5V

Серии дискретных компонентов BiCMOS:
    74LVT		BiCMOS original
    74ALVT
    74ALB

  NAND

'00	ЛА3 ЛА15	4xNAND(2)
'10	ЛА4		3xNAND(3)
'20	ЛА1		2xNAND(4)
'30	ЛА2		1xNAND(8)

7400:

7420:

  NOR

'02	ЛЕ1		4xNOR(2)
'27	ЛЕ4		3xNOR(3)
'23	ЛЕ2		2xNOR(4)
'260	ЛЕ7		2xNOR(5)

  NOT

'04	ЛИ1		6xNOT(1)

Инвертор на триггере Шмидта:

  AND

'08	ЛИ1		4xAND(2)
'11	ЛИ3		3xAND(3)
'21	ЛИ6		2xAND(4)

  OR/Buf

'32	ЛЛ1		4xOR(2)
'34	ЛИ9		6xBUF(1)

  XOR

'86	ЛП5		4xXOR(2)


4.7. МОДЕЛИРОВАНИЕ НА ЭЛЕКТРОННОМ УРОВНЕ И SPICE

Один из основных форматов для обмена электрическими схемами это SPICE
(SPICE - Simulation Program with Integrated Circuit Emphasis)
(SPICE - это программа моделирования радиоэлектронных компонентов).

Большинство програм моделирования поддерживают экспорт и импорт в
текстовой формат SPICE2.

К сожалению модели микроэлектронных приборов "вшиты" в SPICE и
хотя можно тюнить параметры - все равно HDL-AMS языки дают больше контроля
над происходящими процессами.

  Очень краткое описание SPICE языка:

* КОММЕНТАРИЙ
[ТИП_ИМЯ_КОМПОНЕНТА] [УЗЕЛ1] .. [УЗЕЛ_N] [ПАРАМЕТР_1] ... [ПАРАМЕТР_N]
.END		ставится в конце файла

Типы компонентов
 ---------------------------------------------------------------------
Rxx	resistor				резистор
Lxx	inductor				катушка индуктивности
Cxx	capacitor				конденсатор
Vxx	voltage source          		источник напряжения
Ixx	current source				источник тока
Exx	voltage controlled voltage source
Hxx	current controlled voltage source
Fxx	current controlled current source
Gxx	voltage controlled current source
Dxx	diode					диод
Jxx	junction FET				JFET транзистор
Mxx	MOSFET					МОС транзистор
Bxx	GaAsFET					транзистор на арсениде галлия GaAs
Qxx	BJT					биполярный транзистор
 ---------------------------------------------------------------------

  Резистор

 ------------------------------------
Rxx	NODE1	NODE2	RESISTIVITY
R1	1	0	1.0ohm
R3	7	8	4M
 ------------------------------------

  Источник напряжения

 ------------------------------------
Vxx	V_NODE	GND_NODE  VOLTAGE
V1	1	0	  3.0volt
V2	2	3	  4K
 ------------------------------------

  Источник тока

 ------------------------------------
IXX	NODE	NODE	CURRENT
I4	2	4	15m			// 0.015 A
 ------------------------------------

  Конденсатор

 ------------------------------------
Cxx	NODE	NODE	CAPACITY
C1	1	0	1.5u		(microfarad)
C2	2	3	4pF
 ------------------------------------

  Индуктивность

 ------------------------------------
Lxx	NODE	NODE	INDUCTIVITY
L3	1	0	10m
 ------------------------------------

  Voltage controlled voltage source

--------------------------------------
Exx	ONODE	ONODE	INODE	INODE	GAIN
E3	1	2	3	4	5
E4	1	2      (3,	4)	10
--------------------------------------
E3:	V(1-2) = V(3-4) * 5
E4:	V(1-2) = V(3-4) * 10

Для диодов, транзисторов итд используются модели

--------------------------------------
.MODEL	NAME	TYPENAME  (PARAMETER=VALUE,...)
--------------------------------------

TYPENAME is:
    CAP	capacitor
    IND	inductor
    RES	resistor
    D	diode
    NPN	BJT n-p-n
    PNP	BJT p-n-p
    NJF	n-JFET
    PJF	p-JFET
    NMOS	n-channel MOSFET
    PMOS	p-channel MOSFET
    GASFET	GaAs n-JFET
    CORE	non-linear magnetics
    VSWITCH voltage-controlled switch
    ISWITCH	current-controlled switch

  Параметры модели диода

 ------------------------------------
Dxx	+NODE	-NODE	MODEL
D5	5	7	MyDiode
 ------------------------------------

    -------------------------------------------------------------
    IS	Saturation current				A
    N	Emission coefficient                            1
    RS	Parasitic resistance            		Ohm
    CJO	zero-bias p-n capacitance       		Farad
    VJ	p-n potencial                   		V
    M	p-n grading coefficient                 	1
    FC	forward-bias depletion capacitance coefficient  1
    TT	transmit time					sec
    BV	reverse breakdown voltage			V
    IBV	reverse breakdown current			A
    EG	bandgap voltage					eV
    XTI	IS temperature exponent                         1
    KF	flicker noise coefficient                       1
    AF	flicker noise exponent                          1
    -------------------------------------------------------------

  Параметры модели MOSFET

 ------------------------------------
Mxx	DRAIN	GATE	SOURCE	BULK	MODEL
    NODE	NODE	NODE	NODE    NAME
M1	2	3	5	0	NMDideal
 ------------------------------------

    -------------------------------------------------------------
    L	channel length					meter
    W	channel width					meter
    LD	lateral diffusion (length)			meter
    LW	lateral diffusion (width)			meter
    VTO	zero-bias threshold voltage			meter
    KP	transconductance				amp/volt^2
    GAMMA	bulk treshold parameter				volt^(1/2)
    PHI	surface potencial				volt
    LAMBDA	channel-length modulation			1/volt
    RD	drain ohmic resistance				ohm
    RS	source ohnic resistance				ohm
    RG	gate ohmic resistance				ohm
    RB	bulk ohmic resistance				ohm
    RDS	drain-source shunt resistance			ohm
    RSH	drain-source diffusion sheet resistance		ohm
    IS	bulk p-n saturation current			A
    JS	bulk p-n saturation current area		A/meter^2
    PB	bulk p-n potencial				volt
    CBD	bulk-drain zero-bias p-n capacitance		farad
    CBS	bulk-source zero-bias p-n capacitance		farad
    CJ	bulk p-n zero-bias bottom capacitance/area	farad/meter^2
    CJSW	bulk p-n zero-bias perimeter capacitance/area	farad/meter
    MJ	bulk p-n bottom grading coefficient		1
    MJSW	bulk p-n sidewall grading coefficient		1
    FC	bulk forward-bias capacience coefficient	1
    CGSO	gate-source overlap capacitance/channel width	farad/meter
    CGDO	gate-drain overlap capacitance/channel width	farad/meter
    CGBO	gate-bulk overlap capacitance/channel width	farad/meter
    NSUB	substrate dopping density			1/cm^3
    NSS	surface state density				1/cm^2
    NFS	fast surface state density			1^cm^2
    TOX	oxide thickness					meter
    TPG	gate material type (-1=as bulk,+1 opposite, 0 = aluminium)
    XJ	metalurgical junction depth			meter
    UO	surface mobility				cm^2/(V*sec)
    VMAX	maximal drift velocity				meter/sec
    XOC	fraction of channel charge attributed to drain  1
    DELTA	width effect on threshold			1
    KF	flicker noise coefficient                       1
    AF	flicker noise exponent                          1
    .... etc
    -------------------------------------------------------------

  BJT

 ------------------------------------
Qxx	COLLECT	BASE	EMMIT	BULK	  MODEL
    NODE    NODE	NODE    NODE      NAME
Q1	2	3	5	0	  NMDideal
 ------------------------------------

    Параметры модели BJT приводить не будем

  Примеры

-----------------------------
* Simple Circuit
Vin   1  0  3.0volt
R1    1  2  1.0ohm
R2    2  0  2.0ohm
.END
------------------------------

C1    1  0  1pF

Пример схемы CMOS инвертора:
----------------------------------
* Oscilloscope(s)
.PROBE V(14, 0)
R_o_scope_0_0 14 0 1Tohm
.PROBE V(15, 0)
R_o_scope_0_1 15 0 1Tohm

* Function Generator(s)
V_fg_plus 14 0 DC 0V AC 3V
+PULSE(-3V 3V 0 100ns 100ns 50ms 100ms)

* Battery(s)
V1 12 0 DC 5

* 3-Terminal Depletion N-MOSFET(s)
M_N_DM_Q1 15 14 0 0 NMDideal

* 3-Terminal Depletion P-MOSFET(s)
M_P_DM_Q2 15 14 12 12 PMDideal

* Connector(s)
* node = 0, label =
* node = 1, label =
* node = 1, label =
* node = 2, label =
* node = 0, label =

* Misc
.TRAN 1.4ms 700ms 0s 1.4ms

.MODEL NMDideal NMOS(VTO=0 KP=20u LAMBDA=0 PHI=600m GAMMA=0 Rd=0 Rs=0
+IS=10f Cgbo=0 Cgdo=0 Cgso=0 Cbd=0 Cbs=0 PB=800m RSH=0 CJ=0 MJ=500m CJSW=0
+MJSW=500m JS=0 TOX=100n NSUB=0 NSS=0 TPG=1 LD=0 U0=600 KF=0 AF=1 FC=500m
+TNOM=27)

.MODEL PMDideal PMOS(VTO=0 KP=20u LAMBDA=0 PHI=600m GAMMA=0 Rd=0 Rs=0
+IS=10f Cgbo=0 Cgdo=0 Cgso=0 Cbd=0 Cbs=0 PB=800m RSH=0 CJ=0 MJ=500m CJSW=0
+MJSW=500m JS=0 TOX=100n NSUB=0 NSS=0 TPG=1 LD=0 U0=600 KF=0 AF=1 FC=500m
+TNOM=27)

.OPTIONS ITL4=25
.END
----------------------------------


4.8. ТЕХНОЛОГИЯ ИЗГОТОВЛЕНИЯ МИКРОСХЕМ

  Получение Кремния

Сначала готовится слитки чистого кремния.
Кремний получают из SiO2 (песок), через стадию SiCl4 и последущее
востановление углем C.

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

или выращиванием кристалла из раствора:

Полученные слитки режут специальными алмазными пилами на пластины (wafer).

  Обработка пластины

1) Кремниевый субстрат p-типа покрывают слоем SiO2 (желтый на схеме) в
   газовой печи при высокой температуре
2) Сверху накладывается слой фотороезиста (синий)
3) Под действием электромагнитного излучения прошедшего через маску
   фоторезист затвердевает. Не освещенные части фоторезиста остаются без
   изменений
4) Незастывший фоторезист смывается растворителем
5) Верхний слой SiO2 удаляется травлением горячим газом. Остается лишь
   сверхтонкий изолирующий слой
6) Растворитель удаляет фоторезтист
7) Накладывается слой поликристалического кремния
   (этот слой будет служить затвором транзистора)
8) фоторезист
9) маска
10) смыв необлученного фоторезиста
11) травление (поликремний и оксидный слой)
12) удаление фоторезиста
13) Легирование кремниевых углублений фосфором
    (в подложке p-типа образуются зоны n-типа (зеленые).

14) Наносим новый слой SiO2.
    Он будет изолировать структуру транзистора от метализации
15) Покрываем Фоторезистом
16) Облучаем через Маску
17) Смыв незатвердевшего фоторезиста
    (образуются пятна SiO2 в местах будующих контактов)
18) Травление кислотой (открываются окна к областям n-типа и затвору)
19) удаление фоторезиста
20) Покрываем тонким слоем алюминия
21) Покрываем фоторезистом
22) Облучаем через маску
23) Смыв незатвердевшего фоторезиста
24) Травление (метал остаеся только под фоторезистом)
25) Удаление фоторезиста

Шаги 14-25 повторяют для обеспечения нужного количества слоев металлизации.

Пластины перед помещением в печь для создания оксидного слоя:

Пластины нанесение фоторезиста:

Литография:

Пример как выглядит результатирующая структура при 6 слоях металлизации:

  Типовые параметры для Тех процессов

    ----------------------------------------------
    P854	1995	0.35 	Al	Si
    P856	1997	0.25    Al      Si
    P858	1999	0.18  	Al      Si
    P1260	2001	0.13    Cu      Si
    P1262	2003	0.09    Cu      Strained Si
    P1264	2005	0.065   Cu      Strained Si
    P1266	2007	0.045   Cu      Strained Si
    P1268	2009	0.032   Cu      Strained Si
    ----------------------------------------------

Для процесса P1260:

    -----------------------------------------
                        Pitch	Толщина   Aspect
    Уровень		nm      nm        Ratio
    -----------------------------------------
    Isolation	345	450       -
    Polysilicon	319	160       -
    Metal 1		293	280       1.7
    Metal 2,3	425	360	  1.7
    Metal 4		718	570	  1.6
    Metal 5		1064	1200	  1.7
    Metal 6		1143	1200	  2.1
    -----------------------------------------

  После плаcтины

300мм пластина с чипами памяти:

Wafer разрезается на чипы. Как правило алмазной пилой, иногда лазером.

Чипы тестируются.
Так как при изготовлении могли возникнуть дефекты. Например:

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

Затем помещаются в корпус
к ним припаивают ножки и заливают специальной теплопроводящей пастой в
корпусе.

Помещение chipа в корпус:

Припаивание ножек:

Затем корпус закрывают. Chip готов - можно его напаивать на плату.


4.9. ПЕЧАТНЫЕ ПЛАТЫ

PCB (Printed Circuit Board)
Собственно микросхемы и прочие элементы размещают на печатных платах.
Печатная плата - это собственно диэлектрическая основа и металические дорожки
соединяющие компоненты.

Современные печатные платы многослойные (порядка 10 слоев).

Вот так выглядет печатная плата в разрезе.
(мы видим слои с дорожками (медь) и диэлектрические слои):

Как делают дорожки?
Каждый слой покрывают фоторезистом, проецируют маску, затем травят
химическими методами:

Важно соблюдать технологию - что бы не возникли дефекты:

Затем все слои прокладываются диэлектриком и прессуются:

  Разводка

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

  Монтаж элементов

Сквозной:

Поверхносный:


5. ТРИГГЕРЫ

Def
===
    ТРИГГЕР
        устройство имеющее два устойчивых состояния и
        способное под действием входного сигнала скачкообразно
        переходить из одного состояния в другое
        (простейший цифровой автомат способный хранить 1 бит
        информации.

Триггер как черный ящик:

                установочные входы
                (для первоначальной
                инициализации [RESET])

                                   |  |  |
                +-----------+
информационные	входы	      --|	    |--	 Выходы
(для установки информации)    --|	    |--  (как правило прямой и
                  --|           |--  инверсный)
                +-----------+
                   |  |  |
                исполнительные входы
                (для синхронизации)
                [CLK]

        Триггеры
        /       \
    Асинхронные     Синхронные
      latch	       /       \
            По уровню    По фронту
        gated latch  flip-flop

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

Собственно в зарубежной схемотехнике слово триггер (flip-flop) относится
только к "синхронным триггерам по фронту", "асинхронные триггеры" называются
(latch) [защелка]. Синхронные по уровню называются  (gated latch),

            Триггеры (по логике работы)
           /  /| |    |              \
        RS JK T D  комбинированные  сложной
                                    логики
                [RST]	   [J=J1J2J3,
                                K=K1K2K3]

        Триггеры (по внутренней организации)
            /            \
            одноступенчатые     двухступенчатые

Строение одноступенчатого триггера:


5.1. АСИНХРОННАЯ RS-ЗАЩЕЛКА

  Асинхронная RS-защелка

DIN/ANSI

принципиальная схема:

Собственно говоря состоит из логических элементов с обратной связью.

Входы:
R - RESET - сбросить   (значение хранимого байта становится равным 0)
S - SET   - установить (значение хранимого байта становится расным 1)

Выходы:
Q	- хранимый бит данных
Q#	- инверсия хранимого бита данных

    ------+--------------
    S  R  |   Q    Q#
    ------+--------------
    0  0  | lastQ  lastQ#	хранение
    0  1  |   0    1	сброс в 0
    1  0  |	  1    0	установка в 1
    1  1  |	  X    X	неопределенное состояние
    ------+--------------
    1  1  |   0    0	но потом возможны гонки
    ---------------------

таблица истинности:

    ---------------
    S R Q | Q(t+1)
    ------+--------
    0 0 0 | 0
    0 0 1 | 1
    0 1 X | 0
    1 0 X | 1
    1 1 X | X
    ---------------

карта карно:
                SR
        -----------
           |00 01 11 10
          -+------------+
        Q|0| 0  0  X  1 |
         |1| 1  0  X  1 |
           +------------+

RS-защелку можно описать формулой:
Q(t+dt) = S + R#Q(t)

Если одновременно приходит и R и S то состояние защелки неопределено.

Схема состояний:

Рассмотрим работу RS-защелки:
Хранение:

Сброс/установка:

Неопределенное состояние:

Если одновременно и R и S будут равны 1, то тогда Q и Q# будут равны 0.
Если при выходе из состояния RS=11, кто-то R или S останется активным, то защелка
придет в стабильное состояние обусловленное активным входом.
Если же они будут сняты сразу вместе, то могут быть возможны гонки,
когда защелка будет быстро переключаться из одного состояния в другое.

Топология RS-защелки:

Программа на Verilog для ассинхронной RS-защелки:
(на самом деле некорректная т.к. не отслеживается 11)

    module sr_latch (SET, RESET, Q);
    input SET, RESET;
    output Q;
    reg Q;

    always @(RESET or SET)
        if (~RESET)
            Q = 0;
        else if (~SET)
            Q = 1;
    endmodule

Временная диаграмма приведена выше:

  Асинхронная инверсная RS-защелка

DIN/ANSI

В принципе почти тоже самое что RS-защелка, но построена на NAND, и входы
инверсные.
    т.е.	R#   - Reset если = 0
        S#   - Set   если = 0

принципиальная схема:

    ------+--------------
    S# R# |   Q    Q#
    ------+--------------
    0  0  |	  X    X	неопределенное состояние
    0  1  |	  1    0	установка в 1
    1  0  |   0    1	сброс в 0
    1  1  | lastQ  lastQ#	хранение
    ------+--------------
    0  0  |   1    1	но потом возможны гонки
    ---------------------

       __
Работа RS-защелки:
хранение:

сброс/установка:

Неопределенное состояние:

      __
Топология RS-защелки:

CMOS SR-защелка


5.2. RS-ТРИГГЕР

  Синхронная RS-защелка

DIN:
(показаны два варианта с прямой и с инверсной синхронизацией)

принципиальная схема.
К схеме асинхронной RS-защелки добавлена логика которая пропускает
R- и S- только когда C=1 (синхронизация по уровню)

    ---------------------
    S R C |   Q    Q#
    ------+--------------
        X X 0 | lastQ  lastQ#
    0 0 1 | lastQ  lastQ#
    0 1 1 |   0     1
    1 0 1 |	  1     0
    1 1 1 |   X     X
    ---------------------

таблица истинности:
    ---------------
    S R C Q  | Q#
    ---------+-----
    X X 0 0  | 0
    X X 0 1	 | 1
    0 0 1 0  | 0
    0 0 1 1  | 1
    0 1 1 X  | 0
    1 0 1 X  | 1
    1 1 1 X  | X
    ---------------

карта карно:

            SR
          00  01  11  10
         ----------------
      00|  0   0   0   0
      CQ  01|  1   1   1   1
      11|  1   0   X   1
      10|  0   0   X   1

Создание синхронной RS-защелки из асинхронной RS-защелки

  RS-триггер

DIN:
(два варианта - тактирование по фронту '/' и по спаду '\')

Блок-схема RS-триггера:

RS-триггер (работает по фронту):


5.3. JK-ТРИГГЕР

  Синхронная JK-защелка

JK- защелка - это RS-защелка в котором устранена неопределенность:
если J [S] и K [R] одновременно равны 1 то защелка меняет свое состояние

Диаграмма состояний JK-защелки:

принципиальная схема синхронной JK-защелки

    ---------------------
    J K C |   Q    Q#
    ------+--------------
        X X 0 | lastQ  lastQ#
    0 0 1 | lastQ  lastQ#
    0 1 1 |   0     1
    1 0 1 |	  1     0
    1 1 1 | lastQ# lastQ
    ---------------------

карта карно для синхронной JK-защелки

        JK
         00 01 11 10
    ---+--------------
    00 |  0  0  0  0
    CQ  01 |  1  1  1  1
    11 |  1  0  0  1
    10 |  0  0  1  1

  Синхронная JK-защелка с асинхронным сбросом

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

    ------------------------
    J K C RST|   Q    Q#
    ---------+--------------
        X X 0  0 | lastQ  lastQ#
    0 0 1  0 | lastQ  lastQ#
    0 1 1  0 |   0     1
    1 0 1  0 |   1     0
    1 1 1  0 | lastQ# lastQ
    X X X  1 |   0     1
    -------------------------

карта Карно:
                 RJK
        000 001 011 010 110 111 101 100
    ---+--------------------------------
    00 |  0   0   0   0   0   0   0   0
    CQ	01 |  1   1   1   1   0   0   0   0
    11 |  1   0   0   1   0   0   0   0
    10 |  0   0   1   1   0   0   0   0

Создание синхронной JK-защелки из RS-защелки

Синхронная JK-защелка с установкой и сбросом

  JK-триггер

DIN/ANSI
(треугольник значит работает по фронту)

DIN/ANSI
(инверсия и треугольник - значит работает по фронту инверсного сигнала -
то есть по спаду прямого сигнала)

Блок-схема JK-триггера:

JK-триггер (работает по фронту):

VHDL програма для JK-триггера с установочным входом RST

    library ieee;
    use ieee.std_logic_1164.all;

    entity JKFF is
        port(
                CLK, RST, J, K : in std_logic;
                Q : out std_logic);
    end JKFF;

    architecture Example of JKFF is
        signal FF:std_logic;		-- Flip Flop main data
        signal CHG:std_logic;		-- Change symbol
    begin
        process(CLK,RST,CHG)
        begin
            if (RST = '1') THEN
                FF <= '0';
            elsif (CLK'event and CLK = '1') THEN
                CHG <= '1' after 1 ns;
            end if;
            if (CHG = '1') then
                if J = '0' and K = '1' then
                    FF <= '0';
                elsif J = '1' and K = '0' then
                    FF <= '1';
                elsif J = '1' and K = '1' then
                    FF <= not FF;
                elsif J = '0' and K = '0' then
                    FF <= FF;
                end if;
                CHG <= '0' after 1 ns;
            end if;
        end process;
        Q <= FF after 1 ns;
    end Example;

Результат симуляции JK-триггера:

Создание JK-триггера из D-триггера


5.4. D-ТРИГГЕР

  D-защелка

D-защелка имеет вход данных D и синхронизационный вход C.

принципиальная схема D-защелки

    ----------------------
    C  D  |  Q      Q#
    ------+---------------
    0  X  | lastQ  lastQ#
    1  0  |  0      1
    1  1  |  1      0
    ----------------------

Карта Карно:

        CD
        00  01  11  10
     --+----------------
     Q	0 |  0   0   1   0
    1 |  1   1   1   0

Диаграмма состояний D-защелки:

Создание D-защелки из RS-защелки:

Создание DV-защелки (V - вход разрешения) из D-защелки:

Реализация D-защелки на CMOS:

Реализация D-защелки на CMOS:

Топология D-защелки на CMOS:

Примеры реализации сброса для D-защелки на CMOS:

  D-триггер

DIN/ANSI
(пример с одним выходом)

DIN/ANSI
(пример с двумя выходами)

Блок-схема D-триггера:

D-триггер (работает по фронту):

VHDL программа для D-триггера с асинхронным установочным входом RST

    library ieee;
    use ieee.std_logic_1164.all;

    entity DFF is
        port(
                CLK, RST, D : in std_logic;
                Q : out std_logic);
    end DFF;

    architecture Example of DFF is
        signal FF:std_logic;		-- Flip Flop main data
        signal CHG:std_logic;		-- Change symbol
    begin
        process(CLK,RST,CHG)
        begin
            if (RST = '1') THEN
                FF <= '0';
            elsif (CLK'event and CLK = '1') THEN
                CHG <= '1' after 1 ns;
            end if;

            if (CHG = '1') then
                FF <= D;
                CHG <= '0' after 1 ns;
            end if;
        end process;
        Q <= FF after 1 ns;
    end Example;

Результат симуляции:

Verilog программа для D-триггера с установочным входом RESET

    module	DFF(data,clk,reset,q);
        input	data,clk,reset;
        output	q;
        reg	q;

        always @(posedge clk or negedge reset)
        begin
            if (~reset)
                q = 1'b0;
            else
                q = data;
        end
    endmodule;

Топология D-триггера на CMOS:


5.5. T-ТРИГГЕР

  T-защелка

Т-защелка меняет свое состояние при приходе сигнала Т.

    ------------------
      T |  Q      Q#
    ----+-------------
      0 |lastQ  lastQ#
      1 |lastQ# lastQ
    ------------------

Диаграмма состояний T-защелки:

принципиальная схема Т-защелки

  T-триггер

ANSI/DIN
(c одним выходом)

ANSI/DIN
(с двумя выходами)

T-триггер (работает по фронту):

  Построение Т-триггера из D-триггера

VHDL модель T-триггера построенного на базе D-триггера:

    library ieee;
    use ieee.std_logic_1164.all;

    entity TFF is
        port(
                CLK, RST, T : in std_logic;
                Q : out std_logic);
    end TFF;

    architecture Example of TFF is
        component DFF
            port (
                  CLK, RST, D : in std_logic;
                      Q : out std_logic);
        end component;

        signal FF:std_logic;		-- Flip Flop main data
        signal DQ:std_logic;		-- inverse flip flop

    begin
        d1: DFF
        port map(CLK => T,
             RST => RST,
             D   => FF,
             Q   => DQ);

        process (DQ)
        begin
            FF <= not DQ after 1 ns;
        end process;

        Q <= DQ after 1 ns;
    end Example;

Результат симуляции

  Построение Т-триггера из JK-триггера

С синхронизацией:

Чистого D-триггера:


5.6. ГЕНЕРАЦИЯ ИМПУЛЬСОВ ПО ФРОНТАМ

  По фронту

    library ieee;
    use ieee.std_logic_1164.all;

    entity FRONT_RISE is
        port(
                I : in std_logic;
                O : out std_logic);
    end FRONT_RISE;

    architecture Example of FRONT_RISE is
        signal NI:std_logic;	-- Data after inverter
    begin
        process(I)
        begin
            NI <= not I after 5 ns;
        end process;

        O <= I and NI after 1 ns;
    end Example;

Результат симуляции:

  По спаду

    library ieee;
    use ieee.std_logic_1164.all;

    entity FRONT_FALL is
        port(
                I : in std_logic;
                O : out std_logic);
    end FRONT_FALL;

    architecture Example of FRONT_FALL is
        signal NI:std_logic;	-- Data after inverter
    begin
        process(I)
        begin
            NI <= not I after 5 ns;
        end process;

        O <= I nor NI after 1 ns;
    end Example;

Результат симуляции:

  По фронту и по спаду

    library ieee;
    use ieee.std_logic_1164.all;

    entity FRONT_BOTH is
        port(
            I : in std_logic;
            O : out std_logic);
    end FRONT_BOTH;

    architecture Example of FRONT_BOTH is
        signal NI:std_logic;	-- Data after 1st inverter
        signal NI2:std_logic;	-- Data after 2nd inverter
    begin
            process(I)
        begin
            NI <= not I after 5 ns;
        end process;

        process(NI)
        begin
            NI2 <= not NI after 5 ns;
        end process;

        O <= I xor NI2 after 1 ns;
    end Example;


5.7. ДВУХСТУПЕНЧАТЫЕ ТРИГГЕРЫ И ЗАЩЕЛКИ

Двухступенчатые триггеры - комбинация из двух одноступенчатых.
Раньше (например серия 74) предпочитали использовать двухступенчатые триггеры,
сейчас предпочитают одноступенчатые (74LS, 74AS и более поздние).

  Двухступенчатый RS-триггер

Двухступенчатый RS-триггер состоит из двух одноступенчатых защелок.
Первая из них срабатывает когда С = 1, вторая когда С = 0.
(В результате имеем - что бы переключить устройство мы должны иметь
высокий уровень и низкий после него (то есть в общем то это спад)
Таким образом устройство управляется переходом уровней и имеет право
называться уже не защелкой, а триггером.

Пример временной диаграммы для двухступенчатой RS-защелки:

  Двухступенчатый D-триггер

Обозначеник для двухфронтового триггера:

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

Пример временной диаграммы для двухступенчатого D-триггера:

  Summary


5.8. DETFF

THIS SECTION IS UNDER CONSTRUCTION


6. КОМБИНАЦИОННЫЕ СХЕМЫ

DEF
===
    КОМБИНАЦИОННАЯ СХЕМА - схема в которой состояние выходов
    зависит только от состояния входов (т.е. схема не обладает
    какими нибудь состояниями или памятью)

ПОСЛЕДОВАТЕЛЬНАЯ СХЕМА - обладает памятью.

КС								Section
Yes	Логические элементы                                     4.*
Yes	Повторитель (buffer)					4.*
Yes	Тристабильный элемент (tristate)			4.1.2, 4.2
No	Триггеры                                                5.*
No		RS- триггер (синхронный/ассинхронный)		5.1, 5.2
No		JK- триггер (асинхронный/синхронный)		5.3
No		D-  триггер					5.4
No		T-  триггер                                     5.5
Yes	Дешифратор						7
        одноступенчатый
        N- ступенчатый
        пирамидальный
Yes	Шифратор
        7-сегментный индикатор                          7.1
        приоритетный шифратор                           7.2
Yes	Мультиплексор		                                8
Yes	Компаратор						9
Yes	Мажоритарный элемент					10
Yes	Полусумматор                                            11.1
Yes	Сумматор
Yes		полный                                          11.2
Yes		каскад                                          11.3
Yes		с ускоренным переносом                          11.4
    Представление чисел                                     11.5
        обратный код                                    11.5
        знаковые числа                                  11.7
        флаги                                           11.7
        переполнение
    Реализация ДНФ
Yes	Сдвиговый регистр					12
No	Счетчики                                                13
Yes	Умножитель                                              14
    Деление
    Числа с плавающей запятой
        Операции над ними
    Корректирующие коды
    Код Грея
    Byte Endian
    Шины

No	Память
        SRAM  						20
        ROM						20.1
        EPROM						20.2
        DRAM						20.3

Функциональные узлы                                             30
    CPU							30.1
    Устройство ALU          				30.2
    Регистровый файл
    Control Unit
        абстрактный набор команд

Системные узлы
        DMA
    Interrupt processing

Архитектурный уровень
    Все фишки.

НАДО:
    Эмулятор доступа к памяти (cache)
    Эмулятор RISC processora.


6.0. ОБЩИЕ МЕТОДЫ ПОСТРОЕНИЯ КОМБИНАЦИОННЫХ СХЕМ

THIS SECTION IS UNDER CONSTRUCTION

ДНФ, КНФ
XOR-оптимизация
CMOS-оптимизация


6.0.1. ГЛИЧИ

THIS SECTION IS UNDER CONSTRUCTION

Гличи

откуда берутся глитчи?
Рассмотрим пример XOR.

                 A
           ---
        01
           +--+
       B |0|10|
         |1|01|
           +--+

Пусть у нас примерно в одно время изменится и A и B.
Ну тут мы ничего не сделаем.
Получаем результат:

это типа базовая ситуация.

А теперь посмотрим  более сложную функцию

Покроем карту Карно:

При переходе сигналов от одной группы единиц к другой
может возникнуть 0 на выходе (глич).
Поэтому надо защитить переход дополнительным термом:

Все зависит от пути:

THIS SECTION IS UNDER CONSTRUCTION

Как надо оптимизировать схему чтобы их избежать.

  Задержки


7. ДЕШИФРАТОР

Def
===
    Дешифратор - устройство для которого определенный код на входных ногах
    приводит к сигналу на соответствующей выходной ноге
    (Decoder)

Def
===
    Полный дешифратор - дешифратор для которого определенный входной
    код приводит к сигналу на одной уникальной соответсвующей ноге.

  Полный дешифратор 1 в 2

    ------------
    A0  | S0 S1
        ----+-------
    0   | 1  0
    1   | 0  1
    ------------

  Полный дешифратор 2 в 4

ANSI/DIN

    --------------------
    A1 A0 | S0 S1 S2 S3
    ------+-------------
    0  0  | 1  0  0  0
    0  1  | 0  1  0  0
    1  0  | 0  0  1  0
    1  1  | 0  0  0  1
    --------------------

VHDL програма для полного дешифратора 2 в 4

    library ieee;
    use ieee.std_logic_1164.all;

    entity DC_2X4 is
        port(
                A : in std_logic_vector(1 downto 0);
                S : out std_logic_vector(3 downto 0));
    end DC_2X4;

    architecture Example of DC_2X4 is
        signal	  Y: std_logic_vector(3 downto 0);
    begin
        process(A,Y)	-- Very important to set here dependency of Y !!
        begin
            case A is
                when "00" => Y <= "0001";
                when "01" => Y <= "0010";
                when "10" => Y <= "0100";
                when "11" => Y <= "1000";
                when others => Y <= "XXXX";
            end case;
            S <= Y;
        end process;
    end Example;

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

Программа на Verilog для дешифратора 3 в 8:

    module DECODE (A, EN, Y);
        input	EN;
        input	[2:0]	A;
        output  [7:0]	Y;
        reg	[7:0]	Y;

        always @(EN or A)
        begin
            if (!EN)
                Y = 8'b0;
            else
                case (A)
                    3'b000:	 Y = 8'b00000001;
                    3'b001:	 Y = 8'b00000010;
                    3'b010:	 Y = 8'b00000100;
                    3'b011:	 Y = 8'b00001000;
                    3'b100:	 Y = 8'b00010000;
                    3'b101:	 Y = 8'b00100000;
                    3'b110:	 Y = 8'b01000000;
                    default: Y = 8'b10000000;
                endcase
        end
    endmodule

Дешифратор 2x4 с разрешением

Оптимизация на транзисторах

Дешифратор 3x8

Построение дешифратора 4x16 из двух 3x8 с разрешением:

  Типы дешифраторов

           Дешифратор
        /       |       \
  Одноступенчатый Пирамидальный  N-ступенчатый

В дешифраторе для образования логических функций выходов используются
A0..AN и A0#...AN#

Число входов:  N
Число выходов: 2 ** N  (2 в степени N)

  Одноступенчатый - каждый с каждым  (A0*A1#*A2...)
            число элементов = (N * (2 ** N))/2
  N-ступенчатый   - сначала дешифратор на m1 потом на m2
            ((A1*A2#) * (A3*A4))
  Пирамидальный   - как только какие то произведения вычислены они
            используются в каскаде.
            число элементов: ~ 2*((2 ** N) - 1)

              /\
                /    \
              /        \
            A1            A1#
          /  \           /    \
        /      \        /       \
         A1A2   A1A2#      A1#A2     A1#A2#
        /  |     / \       /    \         \  \_____
      /    |   /     \  A1#A2A3 A1A2#A3# A1#A2#A3  A1#A2#A3#
   A1A2A3 A1A2A3# A1A2#A3 A1A2#A3#


7.1. СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР

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

            a
         #########
        #         #
          f #         # b
            #    g    #
             #########
            #         #
           e#         # c
            #    d    #
             #########

7-сегментные индикаторы бывают разных типов (по питанию):

Семисегментный индикатор с общим катодом:

Семисегментный индикатор с общим анодом:

Пример подключения (цифра 5)

                         a b c d e f g

    ####		 1 1 1 1 1 1 0
    #  #
    #  #
    #  #
    ####

       #             0 1 1 0 0 0 0
       #
       #
       #
       #

    #### 		1 1 0 1 1 0 1
           #
        ####
        #
        ####

    ####		1 1 1 1 0 0 1
       #
    ####
       #
    ####

    #  #		0 1 1 0 0 1 1
    #  #
    ####
       #
       #

    ####		1 0 1 1 0 1 1
    #
    ####
       #
    ####

    ####		1 0 1 1 1 1 1
    #
    ####
    #  #
    ####

    ####		1 1 1 0 0 0 0
       #
       #
           #
           #

    ####		1 1 1 1 1 1 1
    #  #
    ####
    #  #
    ####

    ####		1 1 1 1 0 1 1
    #  #
    ####
       #
    ####

    ####		1 1 1 0 1 1 1
    #  #
    ####
    #  #
    #  #

    #   		0 0 1 1 1 1 1
    #
    ####
    #  #
    ####

    ####		1 0 0 1 1 1 0
    #
    #
    #
    ####

       #		0 1 1 1 1 0 1
       #
    ####
    #  #
    ####

    ####		1 0 0 1 1 1 1
    #
    ####
    #
    ####

    ####		1 0 0 0 1 1 1
    #
    ####
    #
    #

Таблица истинности для дешифратора для семисегментного индикатора

    ----------------------------
    A3 A2 A1 A0 | a b c d e f g
    ------------+---------------
    0  0  0  0  | 1 1 1 1 1 1 0
    0  0  0  1  | 0 1 1 0 0 0 0
    0  0  1  0  | 1 1 0 1 1 0 1
    0  0  1  1  | 1 1 1 1 0 0 1
    0  1  0  0  | 0 1 1 0 0 1 1
    0  1  0  1  | 1 0 1 1 0 1 1
    0  1  1  0  | 1 0 1 1 1 1 1
    0  1  1  1  | 1 1 1 0 0 0 0
    1  0  0  0  | 1 1 1 1 1 1 1
    1  0  0  1  | 1 1 1 1 0 1 1
    1  0  1  0  | 1 1 1 0 1 1 1
    1  0  1  1  | 0 0 1 1 1 1 1
    1  1  0  0  | 1 0 0 1 1 1 0
    1  1  0  1  | 0 1 1 1 1 0 1
    1  1  1  0  | 1 0 0 1 1 1 1
    1  1  1  1  | 1 0 0 0 1 1 1
    ----------------------------

Кодер из BCD кода в семисегментный индикатор:

    library ieee;
    use ieee.std_logic_1164.all;

    entity BCD2SSD is
        port (
            src     : in  std_logic_vector(3 downto 0);
                  display : out std_logic_vector(0 to 6);
    end BCD2SSD;

    architecture ARCH of BCD2SSD is
    begin
        process(src)
        begin
            case	src is
                when	"0000"	=> display <= "1111110";
                when	"0001"	=> display <= "1100000";
                when	"0010"	=> display <= "1011010";
                when	"0011"	=> display <= "1110011";
                when	"0100"	=> display <= "1100101";
                when	"0101"	=> display <= "0110111";
                when	"0110"	=> display <= "0111111";
                when	"0111"	=> display <= "1100010";
                when	"1000"	=> display <= "1111111";
                when	"1001"	=> display <= "1110110";
                when	others	=> display <= "0000000";
        end process;
    end ARCH;

Пример схемы дешифратора для семисегментного индикатора:


7.2. ПРИОРИТЕТНЫЙ ШИФРАТОР

(Encoder)

Def
===
    ПРИОРИТЕТНЫЙ ШИФРАТОР - устройство выставляющее на выходе адресс наиболее
приоритетного входа на котором есть входной сигнал.

  старшие линии более приоритетные

GO - Good Output

    -----------------------
    X3 X2 X1 X0 | A1 A0 GO
    ------------+----------
    0  0  0  0  | X  X  0
    0  0  0  1  | 0  0  1
    0  0  1  X  | 0  1  1
    0  1  X  X  | 1  0  1
    1  X  X  X  | 1  1  1
    ----------------------

Логические функции для выходов:

    GO = (X0 + X1 + X2 + X3)
    A1 = X3 + X2
    A0 = X3 + X2# * X1

  младшие линии более приоритетные

    -----------------------
    X3 X2 X1 X0 | A1 A0 GO
    ------------+----------
    0  0  0  0  | X  X  0
    X  X  X  1  | 0  0  1
    X  X  1  0  | 0  1  1
    X  1  0  0  | 1  0  1
    1  0  0  0  | 1  1  1
    -----------------------

Логические функции для выходов:

    GO = (X0 + X1 + X2 + X3)
    A1 = (X3 + X2) * X1# * X0#
    A0 = X3 * X2# * X1# * X0# + X1 * X0#


8. МУЛЬТИПЛЕКСОР

Def
===
    МУЛЬТИПЛЕКСОР - устройство подключающее один из входных каналов
к выходному под воздействием управляющих входов. (Multiplexer)

ANSI/DIN

Простейший мультиплексор 2 в 1.

Если S0 == 0 то  O = D0
Если S0 == 1 то  O = D1

    ----------------
    S0 D1 D0 |  O
    ---------+------
    0  0  0  |  0		// D0
    0  0  1  |  1           // D0
    0  1  0  |  0		// D0
    0  1  1  |  1		// D0
    1  0  0  |  0		// D1
    1  0  1  |  0		// D1
    1  1  0  |  1		// D1
    1  1  1  |  1		// D1
    ----------------

Мультиплексор легко реализуется на CMOS.

Программа для Мультиплексора 2 в 1 на Verilog (switch-level):

    module	mux2_1(out,s,i0,i1);
        output	out;
        input	s,i0,i1;

        wire	sinv;           // sinv = ~ s
        not(sinv,s);
        cmos(out,i0,sinv,s);
        cmos(out,i1,s,sinv);
    endmodule;

Программа на VHDL (для мультиплексора 2x1):

    library ieee;
    use ieee.std_logic_1164.all;

    entity MUX1 is
        port (
            SEL, X0, X1 : in std_logic;
            F	  : out std_logic);
    end MUX1;

    architecture RTL of MUX1 is
    begin
        F <= X0 when SEL = '0' else X1;
    end RTL;

Результаты эмуляции:

Программа на Verilog для мультиплексора 4 в 1:

    module MUX4(C,D,E,F,S,MUX_OUT);
        input	C,D,E,F;
        input	[1:0] S;
        output	MUX_OUT;
        reg	MUX_OUT;

        always @(C or D or E or F or S)
        begin
            case(S)
                2'b00 :   MUX_OUT = C;
                2'b01 :   MUX_OUT = D;
                2'b10 :   MUX_OUT = E;
                default : MUX_OUT = F;
                endcase
        end
    endmodule

Пример мультиплексора 4 в 1:

Его реализация на CMOS:

Мультиплексор 2x1 (4бит)

Реализация логики с помощью MUX:

AND:
    ------------------
       |  0   x |
     y | s0  s1 | out
    ---+--------+-----
     0 | 0*  0  |  0
     0 | 0*  1  |  0
     1 | 0   0* |  0
     1 | 0   1* |  1
    ------------------

OR:
    ------------------
       |  X   1 |
     y | s0  s1 | out
    ---+--------+-----
     0 | 0*  1  |  0
     0 | 1*  1  |  1
     1 | 0   1* |  1
     1 | 1   1* |  1
    ------------------

XOR:
    ------------------
       |  X  X# |
     y | s0  s1 | out
    ---+--------+-----
     0 | 0*  1  | 0
     0 | 1*  0  | 1
     1 | 0   1* | 1
     1 | 1   0* | 0
    ------------------


9. КОМПАРАТОР

Def
===
    КОМПАРАТОР - устройство которое сравнивает две группы сигналов
             (два числа) на равенство.
             [В общем случае не только на равенство]

Простой компаратор сравнивает на равенство.

двухбитный компаратор

    ------------------
    A1 A0 B1 B0  | EQ
    -------------+----
    0  0  0  0   | 1
    0  0  0  1   | 0
    0  0  1  0   | 0
    0  0  1  1   | 0
    0  1  0  0   | 0
    0  1  0  1   | 1
    0  1  1  0   | 0
    0  1  1  1   | 0
    1  0  0  0   | 0
    1  0  0  1   | 0
    1  0  1  0   | 1
    1  0  1  1   | 0
    1  1  0  0   | 0
    1  1  0  1   | 0
    1  1  1  0   | 0
    1  1  1  1   | 0
    ------------------

Результат эмуляции 4х битного компаратора

Более сложные компараторы сравнивает на равенство, больше меньше.
И имеют возможность обединяться в каскады:

Двухбитный компаратор

Таблица истиности такого компаратора:

        A = B
    A > B
    A < B

    -----------------------------------
    A1 A0 B1 B0  I= I> I<  | O= O> O<
    -----------------------+-----------
    0  0  0  0   see below | see below
    0  0  0  1   X  X  X   | 0  0  1
    0  0  1  0   X  X  X   | 0  0  1
    0  0  1  1   X  X  X   | 0  0  1
    0  1  0  0   X  X  X   | 0  1  0
    0  1  0  1   see below | see below
    0  1  1  0   X  X  X   | 0  0  1
    0  1  1  1   X  X  X   | 0  0  1
    1  0  0  0   X  X  X   | 0  1  0
    1  0  0  1   X  X  X   | 0  1  0
    1  0  1  0   see below | see below
    1  0  1  1   X  X  X   | 0  0  1
    1  1  0  0   X  X  X   | 0  1  0
    1  1  0  1   X  X  X   | 0  1  0
    1  1  1  0   X  X  X   | 0  1  0
    1  1  1  1   see below | see below
    -----------------------+-----------
    y  x  y  x   1  0  0   | 1  0  0
    y  x  y  x   0  1  0   | 0  1  0
    y  x  y  x   0  0  1   | 0  0  1
    -----------------------------------

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

Компаратор на равенство, больше, меньше:

Каскад таких устройств:

    +----------+               +----------+
X1  ----|A1	   | 	   X3 -----|A1	      |
X0  ----|A0        |       X2 -----|A0        |
Y1  ----|B1        |       Y3 -----|B1        |
Y0  ----|B0        |       Y2 -----|B0        |
1   ----|I=      O=|---------------|I=      O=|---- EQ
0   ----|I>      O>|---------------|I>      O>|---- GT
0   ----|I<      O<|---------------|I<      O<|---- LT
    +----------+               +----------+

Для каскадов компараторов:
    PEQ2 = EQ1 * EQ0
    PGT2 = GT1 + EQ1 * GT0

    PEQ3 = EQ2 * EQ1 * EQ0
    PGT3 = GT2 + EQ2 * GT1 + EQ2 * EQ1 * GT0


10. МАЖОРИТАРНЫЙ ЭЛЕМЕНТ

Def
===
    МАЖОРИТАРНЫЙ ЭЛЕМЕНТ - элемент производящий "голосование".
    Передает на выход величину соответствующую большинству из
    входных. Всегда имеет нечетное количество входов.

Пример мажоритарного элемента 2 из 3.

    -------------
    F2 F1 F0 | F
    ---------+---
    0  0  0  | 0
    0  0  1  | 0
    0  1  0  | 0
    0  1  1  | 1
    1  0  0  | 0
    1  0  1  | 1
    1  1  0  | 1
    1  1  1  | 1
    ---------+---

F = F1F2 + F1F3 + F2F3

номер отказавшего канала:
    a0 = F1 (+) F3
    a1 = F2 (+) F3

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

Мажоритарный элемент 3 из 5.

    ----------------
    A B C D E  | M5
    -----------+----
    0 0 0 0 0  | 0
    0 0 0 0 1  | 0
    0 0 0 1 0  | 0
    0 0 0 1 1  | 0
    0 0 1 0 0  | 0
    0 0 1 0 1  | 0
    0 0 1 1 0  | 0
    0 0 1 1 1  | 1
    0 1 0 0 0  | 0
    0 1 0 0 1  | 0
    0 1 0 1 0  | 0
    0 1 0 1 1  | 1
    0 1 1 0 0  | 0
    0 1 1 0 1  | 1
    0 1 1 1 0  | 1
    0 1 1 1 1  | 1
    1 0 0 0 0  | 0
    1 0 0 0 1  | 0
    1 0 0 1 0  | 0
    1 0 0 1 1  | 1
    1 0 1 0 0  | 0
    1 0 1 0 1  | 1
    1 0 1 1 0  | 1
    1 0 1 1 1  | 1
    1 1 0 0 0  | 0
    1 1 0 0 1  | 1
    1 1 0 1 0  | 1
    1 1 0 1 1  | 1
    1 1 1 0 0  | 1
    1 1 1 0 1  | 1
    1 1 1 1 0  | 1
    1 1 1 1 1  | 1
    ----------------

    F = ABC + ABD + ABE + ACD +ACE + ADE + BCD + BCE + BDE + CDE

Создание мажоритарного элемента из сумматора:

Логика на мажоритарных элементах:

    +-----+
    x --| M3  |
    y --|     |--  OR
    1 --|     |
    +-----+

    +-----+
    x --| M3  |
    y --|     |--  AND
    0 --|     |
    +-----+

    +-----+
    x --| M5  |
    y --|     |
    z --|     |--- M3
    0 --|     |
    1 --|     |
    +-----+

    +-----+
    x --| M5  |
    y --|     |
    z --|     |-- OR3
    1 --|     |
    1 --|     |
        +-----+

    +-----+
    x --| M5  |
    y --|     |
    z --|     |-- AND3
    0 --|     |
    0 --|     |
    +-----+

Триггеры на мажоритарных элементах:

                                --------------
    +-----+         	x   y | Q{n+1}
    x --| M3  |                 ------+-------
    y --|     |---o--- Q        0   0 |  0
     +--|     |   |             0   1 |  Q{n}
     |  +-----+	  |             1   0 |  Q{n}
     +------------+		1   1 |  1
                --------------

    +-----+
    x --| M5  |
    y --|     |
    0 --|     |---o---- Q
    1 --|     |   |
     +--|     |   |
     |  +-----+   |
     |            |
     +------------+

    +-----+ 		----------------
    x --| M5  |                  x y z  | Q{n+1}
    y --|     |                 --------+-------
    z --|     |---o---- Q        0 0 0  |  0
     +--|     |   |		 0 0 1  |  Q{n}
     |  |     |   |              0 1 0  |  Q{n}
     o--|     |   |		 0 1 1  |  Q{n}
     |  +-----+   |		 1 0 0  |  Q{n}
     |            |		 1 0 1  |  Q{n}
     +------------+		 1 1 0  |  Q{n}
                 1 1 1  |  1
                ----------------

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

    +---------+     +----+
    | Block A |-----|    |
    +---------+     |    |
                    |    |
    +---------+     |    |
    | Block B |-----| M3 |------ Result
    +---------+     |    |
                    |    |
    +---------+     |    |
    | Block C |-----|    |
    +---------+     +----+

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

С увеличением количества входов сложность мажоритарного элемента быстро и сильно
увеличивается. Как правило мажоритарные элементы с числом входов более 7
не производят. (Потому что число перестановок очень быстро растет).

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

Мажоритарный элемент на 3 входа на CMOS
(оптимизация на уровне транзисторов):


10.1. ПОРОГОВЫЙ ЭЛЕМЕНТ

Def
===
    ПОРОГОВЫЙ ЭЛЕМЕНТ - элемент содержащий N входов и 1 выход
    выдающий сигнал 1 на выходе только если как минимум К входов
    равны 1.

    ---------------------
    N    K	  Description
    ---------------------
    1    1	  Buffer			вырожденный случай
    ---------------------
    2    1    ИЛИ                           вырожденный случай
    2    2    И                             вырожденный случай
    ---------------------
    3    1    ИЛИ                           вырожденный случай
    3    2    Мажоритарный элемент
    3    3    И                             вырожденный случай
    ---------------------
    4    1	  ИЛИ                           вырожденный случай
    4    2	  Пороговый элемент
    4    3	  Пороговый элемент
    4    4	  И                             вырожденный случай
    ---------------------
    5    1	  ИЛИ                           вырожденный случай
    4    2	  Пороговый элемент
    5    3	  Мажоритарный элемент
    5    4    Пороговый элемент
    5    5	  И                             вырожденный случай
    ---------------------

    +------+
   X3 --|S(2,4)|
   X2 --|      |
   X1 --|      |---
   X0 --|      |
    +------+

Таблица истинности для порогового элемента с N=4, K=2:

    -------------------
    X3 X2 X1 X0  |  F
    -------------+-----
    0  0  0  0   |  0
    0  0  0  1   |  0
        0  0  1  0   |  0
        0  0  1  1   |  1
        0  1  0  0   |  0
        0  1  0  1   |  1
        0  1  1  0   |  1
        0  1  1  1   |  1
        1  0  0  0   |  0
        1  0  0  1   |  1
    1  0  1  0   |  1
        1  0  1  1   |  1
    1  1  0  0   |  1
    1  1  0  1   |  1
    1  1  1  0   |  1
    1  1  1  1   |  1
    -------------------

    +------+
   X3 --|S(3,4)|
   X2 --|      |
   X1 --|      |---
   X0 --|      |
    +------+

Таблица истинности для порогового элемента с N=4, K=3:

    -------------------
    X3 X2 X1 X0  |  F
    -------------+-----
    0  0  0  0   |  0
    0  0  0  1   |  0
        0  0  1  0   |  0
        0  0  1  1   |  0
        0  1  0  0   |  0
        0  1  0  1   |  0
        0  1  1  0   |  0
        0  1  1  1   |  1
        1  0  0  0   |  0
        1  0  0  1   |  0
    1  0  1  0   |  0
        1  0  1  1   |  1
    1  1  0  0   |  0
    1  1  0  1   |  1
    1  1  1  0   |  1
    1  1  1  1   |  1
    -------------------

Логика на пороговых элементах

    +------+      			+------+
    x --|S(2,4)|                    x --|S(3,4)|
    y --|      |                    y --|      |
    0 --|      |-- OR               1 --|      |-- OR
    1 --|      |                    1 --|      |
    +------+       			+------+

    +------+      			+------+
    x --|S(2,4)|                    x --|S(3,4)|
    y --|      |                    y --|      |
    0 --|      |-- AND              0 --|      |-- AND
    0 --|      |                    1 --|      |
    +------+       			+------+

    +------+      			+------+
    x --|S(2,4)|                    x --|S(3,4)|
    y --|      |                    y --|      |
    z --|      |-- M3               z --|      |-- M3
    0 --|      |                    1 --|      |
    +------+       			+------+


11.1. ПОЛУСУММАТОР

Def
===
    ПОЛУСУММАТОР - комбинированное функциональное устройство с
    двумя входами A и B и двумя выходами (S и P) на которых
    вырабатываются сигналы суммы и переноса.
    [ HA = Half Adder ]

    ------+-------
    A  B  |  P  S
    ------+-------
    0  0  |  0  0
    0  1  |  0  1
    1  0  |  0  1
    1  1  |  1  0
    --------------

Полусумматор на базе XOR:

    library ieee;
    use ieee.std_logic_1164.all;

    entity HSUM1 is
        port(
                B1, B2 : in std_logic;
                C,  S : out std_logic);
    end HSUM1;

    architecture Example of HSUM1 is
    begin
        S <= ((B1 and (not B2)) or ((not B1) and B2));
        C <= B1 and B2;
    end Example;


11.2. ПОЛНЫЙ СУММАТОР

Def
===
    СУММАТОР - комбинированное функциональное устройство
    предназначенное для суммирования чисел
    [а также вычитания, умножения, деления, преобразования
    в обратный код и других операций]
    [ FA = Full Adder ]

ANSI

однобитный сумматор:

    ---------------
    C0 A B | C1 S
    -------+-------
     0 0 0 | 0  0
     0 0 1 | 0  1
     0 1 0 | 0  1
     0 1 1 | 1  0
     1 0 0 | 0  1
     1 0 1 | 1  0
     1 1 0 | 1  0
     1 1 1 | 1  1
    ---------------

Carry Out в пространсве состояний:

Карта карно:

                Cin		         Cin
          0  1		         0  1
        +------+	       +------+
         00 | 0  1 |	    00 | 0  0 |
    AB   01 | 1  0 |	AB  01 | 0  1 |
             11 | 0  1 |            11 | 1  1 |
             10 | 1  0 |            10 | 0  1 |
        +------+		+-----+
           S                      Cout

Сумматор с использованием XOR:

Реализация полного сумматора на VHDL:

    library ieee;
    use ieee.std_logic_1164.all;

    entity SUM1 is
        port(
                A0, B0, P0 : in std_logic;
                P1,  S1 : out std_logic);
    end SUM1;

    architecture Example of SUM1 is
        signal	T:std_logic;
        signal  S:std_logic;
        signal  V:std_logic;
    begin
        T <= (A0 and B0) or (P0 and (A0 or B0));  -- T is carry
        S <= A0 and B0 and P0;
        V <= S or ((not T) and (A0 or B0 or P0));
        P1 <= T;
        S1 <= V;
    end Example;

Реализация полного сумматора на Verilog:

    module fulladd(sum, c_out, a, b, c_in);
        output 	sum, c_out;
        input 	a, b, c_in;

        wire 	s1, c1, c2;

        xor (s1, a, b);
        and (c1, a, b);

        xor (sum, s1, c_in);
        and (c2, s1, c_in);

        xor  (c_out, c2, c1);

    endmodule

Сумматор на базе XOR:

Сумматор на базе AOI:

Сумматор на базе CMOS мультиплексоров:

Сумматор на CMOS:

  Топология


11.3. КАСКАД СУММАТОРОВ

Сумматоры можно объединять в каскад для того чтобы производить
сложение большего числа бит.

Сумматор на 4 бита
ANSI

  Двухбитный сумматор

Реализация двухбитного сумматора на VHDL:

    library ieee;
    use ieee.std_logic_1164.all;

    entity SUM2 is
        port(
                A0, B0, A1, B1, P0 : in std_logic;
                P2,  S1, S2 : out std_logic);
    end SUM2;

    architecture Example of SUM2 is
        component SUM1
            port(
                    A0, B0, P0 : in std_logic;
                    P1,  S1 : out std_logic);
        end component;

        signal	C1:std_logic;

    begin
        sum_0: SUM1
            port map (A0 => A0,
                  B0 => B0,
                  P0 => P0,
                  S1 =>	S1,
                  P1 => C1);

        sum_1: SUM1
                port map (A0 => A1,
                  B0 => B1,
                  P0 => C1,
                  P1 => P2,
                  S1 => S2);
    end Example;

Схема SUM2 (блочная):

Схема SUM2 (логика):

Имплементация SUM2 в Xilinx Virtex-E

Реализация двухбитного сумматора на Verilog:

    module fulladd2(sum, c_out, a, b, c_in);
        output [1:0] sum;
        output c_out;
        input  [1:0] a, b;
        input  c_in;

        wire	c1;	// Internal carry

        fulladd fa0(sum[0], c1,    a[0], b[0], c_in);
        fulladd fa1(sum[1], c_out, a[1], b[1], c1);
    endmodule


11.4. СУММАТОР С УСКОРЕННЫМ ПЕРЕНОСОМ

  Ускоренный перенос

В каскаде сумматоров перенос ползет от младшего бита к старшему.
Поэтому время выполнения сложения равно
        T  = N * Ts
            N  - число бит
            Ts - задержка на однобитном сумматоре

Для этого примера мы полагаем что C0 = 0 (для простоты):

           +-----+
      A0  -| SUM |-- S0
      B0  -|     |--+
           +-----+  | C1
        +-----------+
        |  +-----+
        +--| SUM |
      A1  -|     |-- S1
      B1  -|     |--+
           +-----+  | C2
        +-----------+
        |  +-----+
        +--| SUM |				T = 4 * Ts
      A2  -|     |-- S2
      B2  -|     |--+
           +-----+  | C3
        +-----------+
        |  +-----+
        +--| SUM |
      A3  -|     |-- S3
      B3  -|     |-- C4
           +-----+

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

Для этого примера мы полагаем что C0 = 0 (для простоты):
               +-----+
          A0  -| SUM |-- S0
      +-----+	  B0  -|     |
      |     |	       |     |
A0 ---|	    |	       +-----+
B0 ---|	    |	       +-----+
      |Fast |	  A1  -| SUM |-- S1
A1 ---|Carry|	  B1  -|     |
B1 ---|	    |----------|     |			T = Tl + Ts
      |	    |	 C1    +-----+
A2 ---|	    |	       +-----+
A3 ---|	    |	  A2  -| SUM |-- S2
      +-----+	  B2  -|     |
       |   +-----------|     |
       |     C2	       +-----+
       |	       +-----+
       |	  A3  -| SUM |-- S3
       |	  B3  -|     |
       +---------------|     |-- C4
      C3	       +-----+

Формула для ускоренного переноса

    C1 = A0*B0
    C2 = A1*B1 + A1*A0*B0 + B1*A0*B0
    C3 = A2*B2 + A2*A1*B1 + A2*A1*A0*B0 + A2*B1*A0*B0
           + B2*A1*B1 + B2*A1*A0*B0 + B2*B1*A0*B0

    (собственно ускоренный перенос занимает 3-4 вентиля)

    но с ростом разрядности функция ускоренного переноса требует
все больше и больше места и Tl тоже растет.

Пример схемы сумматора с ускоренным переносом:

Реализация на Verilog:

    module fulladd4(sum,cout,a,b,cin);
        output	[3:0] sum;
        output	cout;
        input	[3:0] a,b;
        input	cin;

        wire	p0,g0,p1,g1,p2,g2,p3,g3;
        wire	c4,c3,c2,c1;

        assign	p0 = a[0] ^ b[0],
            p1 = a[1] ^ b[1],
            p2 = a[2] ^ b[2],
            p3 = a[3] ^ b[3];

        assign	g0 = a[0] & b[0],
            g1 = a[1] & b[1],
            g2 = a[2] & b[2],
            g3 = a[3] & b[3];

        assign  c1 = g0 | (p0 & cin),
            c2 = g1 | (p1 & g0) | (p1 & p0 & cin),
            c3 = g2 | (p2 & g1) | (p2 & p1 & p0 & cin),
            c4 = g3 | (p3 & g2) | (p3 & p2 & g1) |
                          (p3 & p2 & p1 & g0) |
                          (p3 & p2 & p1 & p0 & cin);
        assign	sum[0] = p0 ^ cin,
            sum[1] = p1 ^ c1,
            sum[2] = p2 ^ c2,
            sum[3] = p3 ^ c3;

        assign	cout = c4;
    endmodule

С другой стороны при очень большой разрядности функции ускоренного переноса
получаются очень громоздкими (много места на кристалле), поэтому пользуются
комбинированными методами: сумматор делят на блоки с ускоренным переносом
(например по m бит [обычно по 4])

Для этого примера мы полагаем что C0 = 0 (для простоты):

        +------+
               | SUM4 |==== S3..S0
    A3..A0  ====| fast |
    B3..B0  ====|carry |---+
        +------+   |  C4
         +-------------+
         |	+------+
            +--| SUM4 |==== S7..S4
    A7..A4  ====| fast |
    B7..B4  ====|carry |---+
        +------+   | C8
         +-------------+
         |	+------+
            +--| SUM4 |==== S11..S8
   A11..A8  ====| fast |
   B11..B8  ====|carry |---+
        +------+   | C12
         +-------------+
         |	+------+
            +--| SUM4 |==== S15..S12
   A15..A12 ====| fast |
   B15..B12 ====|carry |---- C16
        +------+

    Время работы такого блока равно: Tl + Ts
    где  Tl - время работы схемы ускоренного переноса

    Полное же время работы сумматора в этом случае равно:

        T = (N / m) * (Ts + Tl)

Примем:
    N = 32
    m = 4
    Ts = Tl	(это почти верно)

    без ускоренного переноса:  T = 32 * Ts
    c ускоренным переносом:    T = (32 / 4) * (Ts + Tl)
                     = 8 * (Ts + Ts) = 16 * Ts
                   мы сократили время выполнения вдвое

Пример:
    N = 32
    m = 5
    Ts = Tl

    без ускоренного переноса:  T = 32 * Ts
    c ускоренным переносом:    T = (32 / 5) * (Ts + Tl)
                     = 7 * (Ts + Ts) = 14 * Ts

  Условный сумматор

Как еще убыстрить схему:

    +------+
Axx   --| FAST |
Bxx   --|CARRY |------------+
    +------+            |
                        |
    +------+            |
1   ----| SUM  |	 +-----+
Ai  ----|      |---------| MUX |
Bi  ----|      |         |     |
    +------+         |     |-------- Si
                     |     |
    +------+         |     |
Ai  ----|HSUM  |---------|     |
Bi  ----|      |         +-----+
    +------+

Условный сумматор:

Время работы сумматора и Fast Carry логики примерно одинаковое.
Мы можем вычислить сумму в условии прихода переноса и в условии
его отсутствия, а паралельно рассчитать быстрый перенос. (Условный сумматор)
Затем просто выбрать правильный результат мультиплексором 2x1 (это быстро)

Cуммарно время выполнения уменьшается с Tl + Ts =~ 2Ts до max(Ts,Tl) + Tmux

        2Ts > Ts + Tmux

мы снова выиграли.

Пример 16-битного условного сумматора:

  Сравнение сумматоров

Сравнение сумматоров:


11.5. СУММАТОРЫ С БЫСТРЫМ РАСПРОСТРАНЕНИЕМ ПЕРЕНОСА

  Сумматор на мультиплексоре

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

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

Транзисторная схема сумматора с буффером на мультиплексоре:

Трехбитный сумматор с распространением переноса на мультиплексоре.

  MCC

MCC (Manchester Carry Chain)

Часто используют MCC схему, заранее предсказывая переносы где возможно:

Идея MCC:
Есть сумматор для конкретного бита:

Выход Carry для обычного HA в каскде:

Kill		K: C{i+1} = 0,   если Ai = 0 и Bi = 0
Generate	G: C{i+1} = 1,   если Ai = 1 и Bi = 1
Proporgate	P: С{i+1} = C{i} если (Ai = 1 и Bi = 0)	или (Ai = 0, Bi = 1)

    ---------
    A  B   C
    ---------
    0  0 | K
    0  1 | P
    1  0 | P
    1  1 | G
    ---------

В зависимости от значений операндов в этом бите мы можем придти к одной
из 3 ситуаций:

    Kill		на выходе не будет Сarry
    Generatre       на выходе будет Carry
    Proporgate	на выходе будет Carry от младшего разряда

MCC сумматор обрабатывает эти возможности электрически.
Потому что время прохождения тока через транзистор гораздо быстрее работы
логического элемента.

  Сумматор Скланского

Brent Kung Cell
Вычисляет перенос для двух блоков FA-cells.
Вход по 2 бита переноса снизу и из текущих:

    ---------------
    eg  ed | Result
    ---------------
    K   K  | K
    K   P  | K
    K   G  | K
    P   K  | K
        P   P  | P
        P   G  | G
        G   K  | G
        G   P  | G
        G   G  | G
    ---------------

Генератор переноса Брента-Кунга (Brent-Kung):

Генератор переноса Когга-Стоуна (Kogge-Stone):

Сумматор Скланского - регулярная структура сумматора построенная на ячейках
Брента-Кунга.

Сумматор Скланского (Sklansky):


11.6. ВЫЧИТАНИЕ

  Снова об дополнительном коде

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

Идея:	X + (-X) = 0
    -X = 0 - X
    -X = 2^m - |X|		дополняет |X| до 2^m

Как образуется дополнительный код:

    - X = (NOT X) + 1

При этом старший бит числа показывает знак:

    +-+-------------+
    |S|		|
    +-+-------------+

    Если S = 0 то число положительное
    Eсли S = 1 то число отрицательное

Рассмотри байт (8 бит):
    ----------------------------------------------------------------
        X		X#		-X = (X#+1)
    Число	Двоичное	Инверсия	Обратный код	Число
    ----------------------------------------------------------------
    0	0000 0000	1111 1111	0000 0000	0
    1	0000 0001	1111 1110	1111 1111	-1
    2	0000 0010	1111 1101	1111 1110	-2
    15	0000 1111	1111 0000	1111 0001	-15
    127	0111 1111	1000 0000	1000 0001	-127
    -128	1000 0000	0111 1111	1000 0000	-128 спец случай
    -3	1111 1101	0000 0010	0000 0011	3
    -1	1111 1111	0000 0000	0000 0001	1
    ----------------------------------------------------------------

Пример другой разрядности

16-бит  Число	Bin			Hex
    1	00000000 000000001 	0001
    -1	11111111 111111111	FFFF

 ----------------------------------------------------------------------
Разрядность	   Беззнаковое			     Знаковое
бит		Min		Max		Min		Max
 ----------------------------------------------------------------------
8		0		255		-128		127
16		0		65535		-32768		32767
32		0		4294967295	-2147483648	2147483647
 ----------------------------------------------------------------------

Сумматор складывает числа в дополнительном коде.
Если складывает то может и вычитать:

    X - Y = X + (-Y) = X + (NOT Y) + 1

  Вычитание

Ячейка вычитателя на базе XOR:

Схема условной инверсии:

Поскольку вычитание зто:  A - B = A + B# + 1, то
схема для вычитания A - B:

       Vcc     - это дает единицу в C0.
       ___
    |
    |      +-----+
    +------| SUM |
      +	  A0 --|     |-- S0
B0  --|>o------|     |--+
      +	       +-----+  | C1
        +-----------+
        |  +-----+
        +--| SUM |
      +	  A1 --|     |-- S1
B1  --|>o------|     |--+
      +	       +-----+  | C2
        +-----------+
        |  +-----+
        +--| SUM |
      +	  A2 --|     |-- S2
B2  --|>o------|     |--+
      +	       +-----+  | C3
        +-----------+
        |  +-----+
        +--| SUM |
      +	  A3 --|     |-- S3
B3  --|>o------|     |-- C4
      +	       +-----+

Схема сложения и вычитания

Схема вычисления -X (negate):


11.7. ОТКУДА БЕРУТСЯ ФЛАГИ?

В процессорах используются флаги (специальные биты которые устанавливаются
в зависимости от результата операции).

  Флаги переноса и знака

Рассмотрим сумматор (на примере 4 бит):

Операции:

    Сложение	A+B		A+B
    Вычитание	A+B#+1          A-B
    Negate		0+B#+1          -B

           +-----+
      C0  -| SUM |
      A0  -|     |-- S0
      B0  -|     |--+
           +-----+  | C1
        +-----------+
        |  +-----+
        +--| SUM |
      A1  -|     |-- S1
      B1  -|     |--+
           +-----+  | C2
        +-----------+
        |  +-----+
        +--| SUM |
      A2  -|     |-- S2
      B2  -|     |--+
           +-----+  | C3
        +-----------+
        |  +-----+
        +--| SUM |
      A3  -|     |-- S3	(Sign Flag)   знак числа результата  SF
      B3  -|     |-- C4	(Carry Flag)  самый старший перенос  CF
           +-----+

Carry	- флаг переноса
Sign	- флаг знака

  Флаг переполнения

При работе со знаковыми числами у нас может возникнуть ситуация выхода
чисел из диапазона (переполнение):

    -------------------------------------------------------
                                Carry	Carry	Overflow
                  8/7    7/6
    A   +   B    	=	N+1/N   N/N-1   Переполнение
    -------------------------------------------------------
    02  +	04	= 06      0	 0	0
    80  +   12	= 92	  0	 0      0
    80  +   FF 	= 7F	  1      0	1
    7F  +   02	= 81	  0	 1	1
    FF  +   FF	= FE	  1	 1	0
    -------------------------------------------------------

перепонение возникает когда у нас:
    Carry (N+1/N)  !=  Carry(N/N-1)		при операции на N разрядах
и не возникает когда:
    Carry (N+1/N)  ==  Carry(N/N-1)

таким образом флаг переполнения Overflow Flag:

    OF = Carry(N+1/N) XOR Carry(N/N-1)

пример для четырехбитного сумматора:

           +-----+
      C0  -| SUM |
      A0  -|     |-- S0
      B0  -|     |--+
           +-----+  | C1
        +-----------+
        |  +-----+
        +--| SUM |
      A1  -|     |-- S1
      B1  -|     |--+
           +-----+  | C2
        +-----------+
        |  +-----+
        +--| SUM |
      A2  -|     |-- S2                     +-----+
      B2  -|     |--+-----------------------|(+)  |----- OF
           +-----+  | C3                 +--| XOR |     флаг
        +-----------+                    |  +-----+     переполнения
        |  +-----+                       |
        +--| SUM |                       |
      A3  -|     |-- S3  (SF) 	     |
      B3  -|     |------+-- C4  (CF)     |
           +-----+      |                |
                        +----------------+

  Флаг нуля

Zero flag: Если результат операции равен нулю, то флаг нуля = 1.

           +-----+
      C0  -| SUM |   S0
      A0  -|     |----------------------+
      B0  -|     |--+                   |
           +-----+  | C1                |
        +-----------+                   |
        |  +-----+                      |
        +--| SUM |   S1                 |
      A1  -|     |------------------+   |   +-----+
      B1  -|     |--+               |   +---| NOR |
           +-----+  | C2            +-------|     |---- ZF (Zero flag)
        +-----------+               +-------|     |     флаг нуля
        |  +-----+                  |   +---|     |
        +--| SUM |	 S2		|   |	+-----+
      A2  -|     |------------------+   |
      B2  -|     |--+                   |
           +-----+  | C3                |
        +-----------+                   |
        |  +-----+                      |
        +--| SUM |  S3                  |
      A3  -|     |----------------------+
      B3  -|     |-- C4
           +-----+

  Все вместе

схема сложения:

схема вычитания:

схема сложения и вычитания:

результат симуляции схемы сложения/вычинания:

  Флаг четности

    PF (Parity Flag)
        = 0 Parity Even  (число единичных битов четное)
        = 1 Parity Odd   (число единичных битов нечетное)

  Вспомогательный Carry флаг

    HF (Half Carry Flag) или
    AF (Auxillary Carry Flag)
        = 1 если есть перенос между 3 и 4 разрядом
        = 0 если нету переноса между 3 и 4 разрядом

HF используется для поддержки BCD-арифметики
Инструкции типа DAA и DAS используют этот флаг.


11.8. СУММАТОР НЕИЗВЕСТНОГО РАЗМЕРА НА HDL

  Описание Generic сумматора VHDL

    library ieee;
    use ieee.std_logic_1164.all;

    entity add_N is
        generic(N: positive);
        port(
            A: in std_logic_vector((N-1) downto 0);
            B: in std_logic_vector((N-1) downto 0);
            X: out std_logic_vector((N-1) downto 0);
            C: out std_logic
        );
    end add_N;

    architecture Example of add_N is

        component SUM1
            port(
                    A0, B0, P0 : in std_logic;
                    P1,  S1 : out std_logic);
        end component;

        signal	IC: std_logic_vector(N downto 0);
        begin
        IC(0) <= '0';

        stages : for i in 0 to (N-1) generate
                add: SUM1
                port map( A0 => A(i),
                  B0 => B(i),
                  S1 => X(i),
                  P0 => IC(i),
                  P1 => IC(i+1));
        end generate stages;
        C <= IC(N);
    end Example;

  Конкретизация Generic сумматора на VHDL

    library ieee;
    use ieee.std_logic_1164.all;

    entity add6 is
        port(
            A6: in std_logic_vector(5 downto 0);
            B6: in std_logic_vector(5 downto 0);
            X6: out std_logic_vector(5 downto 0);
            C6: out std_logic
        );
    end add6;

    architecture Example of add6 is

        component add_N is
            generic(N: positive);
            port(
                A: in std_logic_vector((N-1) downto 0);
                B: in std_logic_vector((N-1) downto 0);
                X: out std_logic_vector((N-1) downto 0);
                C: out std_logic);
        end component;
    begin
            U6:  add_N
             generic map (N => 6)
             port map(
                    A => A6,
                    B => B6,
                    X => X6,
                    C => C6);
    end Example;

Результат синтеза:

Имплементация в Xilinx VIRTEX-E:

  Описание Generic сумматора Verilog

    module adder(cout,sum,a,b,cin);
    parameter Size = 8;
    output	cout;
    output [Size-1:0] sum;
    input	cin;
    input [Size-1:0] a,b;
    assign {cout,sum} = a + b + cin;
    endmodule;

  Конкретизация Generic сумматора на Verilog

    adder #(16) adder_16(cout_A,
                 sum_A,
                 a_A,
                 b_A,
                 cin_A);


11.9. ПОСЛЕДОВАТЕЛЬНЫЙ СУММАТОР

Чтобы суммировать много битов не обязательно делать параллельный сумматор
(много ресурсов), а можно сделать однобитный последовательный (мало
ресурсов, но много времени.

Схема последовательного сумматора:
(похож на паралельный но присутствуют схемы синхронизации)

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

Вообще это общий принцип:

    Работа = Ресурсы * Время

При постоянном объеме работы отношение время/ресурсы может быть различным:

     R	^            	      R	^
    |--+                    |
    |XX|                    |
    |XX|                    |----+
    |XX|                    |XXXX|
    |XX|                    |XXXX|
    +----------->           +------------>
                T                        T

    больше железа   	меньше железа
    работает быстрее	работает медленнее
        обьем работы одинаковый


11.10. BCD СУММАТОР

В принципе можно строить не только двоичные сумматоры, а сумматоры
по определенному модулю.

Пример BCD сумматор

сумматор для BCD с дополнением до 3:

Мы видим что он значительно проще чем сумматор для BCD.


11.11. СУММАТОР С НАСЫЩЕНИЕМ

THIS SECTION IS UNDER CONSTRUCTION

Используется в Multimedia Units для арифметики с насыщением.

Если Overflow то возвращается максимально возможное.

    -------------------------------------------------------
                                Carry	Carry	Overflow
                  8/7    7/6
    A   +   B    	=	N+1/N   N/N-1   Переполнение
    -------------------------------------------------------
    80  +   FF 	= 7F	  1      0	1
    7F  +   02	= 81	  0	 1	1
    -------------------------------------------------------

        +-----+
       C0 --| SUM |
       A0 --|     |                            +-----+
       B0 --|     |                   1000 ====| MUX |
            |     |                            |     |
       A1 --|    S|============================|     |
       B1 --|     |                            |     |
            |     |                   0111 ====|     |==========  RESULT
       A2 --|     |		+----+             |     |
       B2 --|     |         | CD |             |     |
        |   C3|---------|    |-------------|     |
       A3 --|     |         |    |-------------|     |
       B3 --|   C4|---------|    |  control    +-----+
        |   OF|---------|    |
        +-----+         +----+

    -----------------------------------
    OF	C4	C3	Result
    -----------------------------------
    0	X	X	S
    1	1	0	max positive 	0111
    1	0	1	min negative 	1000
    -----------------------------------


11.12. СУММАТОРЫ/ВЫЧИТАТЕЛИ ДЛЯ ДРУГИХ (НЕ ДОПОЛНЕНИЕ ДО ДВУХ) СХЕМ

THIS SECTION IS UNDER CONSTRUCTION

Дополнение до 1:

Прямой код:


11.13. ИСПОЛЬЗОВАНИЕ СУММАТОРО-ПОДОБНЫХ СТРУКТУР ДЛЯ ВЫПОЛНЕНИЯ ПРОЧИХ ОПЕРАЦИЙ

THIS SECTION IS UNDER CONSTRUCTION

Некоторые Операции которые делают через сумматор:

Добавляем Saturated операции:

Добавляем операции с Carry:

Добавляем вычитание:

  ABS

Вычисление абсолютной величины числа (модуля)

if (A[15]) result = saturate(INV({A[15],A[15:0]}) + A[15];
else	   result = A[15:0] + A[15];		// в этом случае A[15] = 0

  MIN/MAX

Вычисление минимума или максимума

Вычисление MAX:

  AVD

Absolute Value of Difference:


11.14. ИСПОЛЬЗОВАНИЕ СУММАТОРОВ ДЛЯ RSN

В секции 3.18 рассматривались RSN (Residue Number System).
Соответсвенно для RSN:

  Сложение/Вычитание

Сумматор по модулю M в общем виде:

0 <= X,Y < M < 2^N

существует два варианта:

X + Y < M,  тогда  X + Y + 2^N - M < 2^N   и CF = 0, результат = X + Y

X + Y >= M, тогда  X + Y + 2^N - M >= 2^N  и CF = 0, результат = X + Y - M = (X + Y) mod M

если M близко к адрессной сетке, то надо учитывать еще и случай:
X + Y >= 2^N

Вычитание по модулю M в общем виде:

0 <= X, Y < M < 2^N

существует два варианта:

X - Y >= 0, тогда CF = 0, и результат = X + Y
X - Y <  0, тогда CF = 1, и результат = X - Y + M = (X - Y) mod M

  2^N - 1

В случае когда M = 2^N - 1, а это очень удачный выбор, поскольку используем почти
все возможные значения:

(X + Y) mod M = ((X + Y) mod (2^N)) + ((X + Y) >= 2^N)
то есть если вылезли за пределы то прибавляем единичку.

Но гораздо удобнее происходит умножение:

(X * Y) mod M = ((X * Y) mod (2^N)) +mod(M) ((X * Y) / 2^N)
т.е.
(X * Y) mod M =  (LO(X*Y) + HI(X*Y)) mod M

Для RSN надо выбирать взаимно простые модули.
например:	2^32-1, 2^31-1, 2^29-1, 2^27-1, 2^25-1

Сумматор по модулю 2^N-1 (на рисунке по модулю 255):

Сумматор по модулю 2^N+1 (на рисунке по модулю 257):

  Умножение

  Конвертация в RSN

Конвертор в модуль 2^N-1 (на рисунке в модуль 63):

Конвертер в модуль 2^N+1 (на рисунке в модуль 65):

  Конвертация из RSN


12. СДВИГОВЫЙ РЕГИСТР

  Сдвиги

Типичные виды сдвигов:

  SHL

        +----------+
        <-- |          | <-- 0	SHL	Shift Left Logical
        +----------+		SAL	Shift Arithmetic Left

  SHR

        +----------+
       0  ->|          |-->		SHR	Shift Right Logical
        +----------+

  SAR

        +-+--------+
         +->|S|        |-->		SRA	Shift Right Arithmetic
         |	+-+--------+
         |   |
         +---+
        повторяем
        знаковый бит

  Вращения

Кроме сдвигов есть еще и Rotates - это когда регистр "вращается".
(т.е. регистр сдвигается так что младший бит становится старшим и
наоборот).

Есть вращения обычные и есть вращения через Carry Flag - специальный
бит микропроцессора в регистре состояния.

  ROL

        +----------+
        +-- |          | <--+	ROL	Rotate Left
        |	+----------+	|
        +-------------------+

  ROR

        +----------+
        +-> |          |  --+	ROR	Rotate Right
        |	+----------+	|
        +-------------------+

  RCL

    +----------+    +--+
    +-- |          | <- |CF|< --+	RCL	Rotate with Carry Left
    |	+----------+    +--+	|
    +---------------------------+

  RCR

    +----------+    +--+
    +-> |          | -> |CF| ---+	RCR	Rotate with Carry Right
    |	+----------+    +--+	|
    +---------------------------+

  Паралельные сдвиговые регистры

Пример простого логического сдвигового регистра:

    --------------------------------
    DIR D0 D1 D2 D3  |  S0 S1 S2 S3
    -----------------+--------------
    0   A  B  C  D   |  B  C  D  0
    1   A  B  C  D	 |  0  A  B  C
    --------------------------------

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

Пример реализации сдвигового регистра на VHDL:
(Поддерживает Logical Shift и Rotate на 1 бит)

    library	IEEE;
    use	IEEE.std_logic_1164.ALL;

    entity SHIFT is
        port(
            a   : in  std_logic_vector(15 downto 0);
                 sel : in  std_logic_vector(2  downto 0);
                -- Command to shiter
                -- 000 SHL
                -- 001 SHR
                -- 010 ROL
                -- 011 ROR
                -- 1XX pass (no shift)
                 y   : out std_logic_vector(15 downto 0)
        );
    end SHIFT;

    architecture RTL of SHIFT is
    begin
        shiftprocess: process(a,sel)
        begin
            case sel is
                WHEN "000" =>		-- SHL
                    y <= a(14 downto 0) & '0' after 1 ns;
                WHEN "001" =>		-- SHR
                    y <= '0' & a(15 downto 1) after 1 ns;
                WHEN "010" =>		-- ROL
                    y <= a(14 downto 0) & a(15) after 1 ns;
                WHEN "011" =>		-- ROR
                    y <= a(0) & a(15 downto 1) after 1 ns;
                WHEN OTHERS =>  	-- pass it
                    y <= a;
            end case;
        end process;
    end RTL;

Как сдвигать больше чем на 1 бит?
Используется каскад.

Пример:
16 битный сдвиговый регистр, сдвигает влево на любое число бит:

    library	ieee;
    use	ieee.std_logic_1164.all;
    use	ieee.std_logic_arith.all;

    entity	shl16 is
        port(
            DIN: in std_logic_vector(15 downto 0); 	 -- Data input
            S  : in std_logic_vector(3 downto 0);	 -- Shift ammount
            DOUT: out std_logic_vector(15 downto 0)  -- Data Output
             );
    end	shl16;

    architecture ARCH of shl16 is
        signal	X,Y,Z : std_logic_vector(15 downto 0);  -- Temporary
    begin
            process(DIN,S)
        begin
            if S(0) = '1' then
                X <= DIN(14 downto 0) & "0";
            else
                X <= DIN;
            end if;
        end process;

        process(S,X)
        begin
            if S(1) = '1' then
                Y <= X(13 downto 0) & "00";
            else
                Y <= X;
                end if;
        end process;

            process(S,Y)
        begin
            if S(2) = '1' then
                Z <= Y(11 downto 0) & "0000";
            else
                Z <= Y;
            end if;
        end process;

        process(S,Z)
        begin
            if S(3) = '1' then
                DOUT <= Z(7 downto 0) & "00000000";
            else
                DOUT <= Z;
            end if;
        end process;
    end ARCH;

Можно также иметь управляющий бит который будет показывать направление
cдвига:

DIR
  |		DATA
  |               |
  |		  V
  |	+-----------------------+
  +--->	|  shift      4		| < ---------  S3
  |	+-----------------------+      +-----  S2
  |		  |                    |+----  S1
  |		  V                    ||+---  S0
  |	+-----------------------+      |||
  +--->	|  shift      3		| < ---+||
  |	+-----------------------+       ||
  |	          |                     ||
  |		  V                     ||
  |	+-----------------------+       ||
  +--->	|    shift    2		|<------+|
  |	+-----------------------+        |
  |		  |                      |
  |		  V                      |
  |	+-----------------------+        |
  +--->	|    shift    1		|<-------+
    +-----------------------+
          |
          V
        RESULT

Пример:
Вращающий 16бит регистр сдвига в любон направлении на любое число бит:

    library	ieee;
    use	ieee.std_logic_1164.all;
    use	ieee.std_logic_arith.all;

    entity	rot16 is
        port(
            DIN : in std_logic_vector(15 downto 0);	 -- Data input
            S   : in std_logic_vector(3 downto 0);	 -- Shift ammount
            DIR : in std_logic;			 -- Direction (0 = Left, 1 = Right)
            DOUT: out std_logic_vector(15 downto 0)  -- Data Output
             );
    end	rot16;

    architecture ARCH of rot16 is
        signal	X,Y,Z : std_logic_vector(15 downto 0);	-- Temporary buses
    begin
        process(DIN,S,DIR)
        begin
            if S(0) = '1' then
                if DIR = '0' then
                    X <= DIN(14 downto 0) & DIN(15);
                else
                    X <= DIN(0) & DIN(15 downto 1);
                end if;
            else
                X <= DIN;
            end if;
        end process;

        process(S,X,DIR)
        begin
            if S(1) = '1' then
                if DIR = '0' then
                    Y <= X(13 downto 0) & X(15 downto 14);
                else
                    Y <= X(1 downto 0)  & X(15 downto 2);
                end if;
            else
                Y <= X;
            end if;
        end process;

        process(S,Y,DIR)
        begin
            if S(2) = '1' then
                if DIR = '0' then
                    Z <= Y(11 downto 0) & Y(15 downto 12);
                else
                    Z <= Y(3 downto 0)  & Y(15 downto 4);
                end if;
            else
                Z <= Y;
            end if;
        end process;

        process(S,Z,DIR)
        begin
            if S(3) = '1' then
                -- rotate by 8 bit is same values for
                -- both rotate right or left
                DOUT <= Z(7 downto 0) & Z(15 downto 8);
            else
                DOUT <= Z;
            end if;
        end process;
    end ARCH;

Кроме каскада возможна схема с мультиплексорами:

  Barrel Shifter

Оптимизированный на транзисторах сдвиговый регистр на любое число бит.

  Последовательные сдвиговые регистры

Последовательные сдвиговые регистры - совокупность триггеров и связей
между ними. Каждый такт данные сдвигаются на один бит.
(Раньше экономя транзисторв в микропроцессорах делали последовательные
сдвиговые регистры (например в 80286).

Последовательные сдвиговые регистры:

Сдвиговый регистр на JK-триггерах:

Сдвиговый регистр на D-триггерах

  Имплементация различных типов сдвигов


13. СЧЕТЧИКИ

Счетчики строятся на T-триггерах

  Двоичный Счетчик N..0

Простой счетчик (3 бит) считающий в обратную сторону

  Двоичный Счетчик 0..N

  Паралельные счетчики

Последовательный счетчик:
(сигналы разрешения двигаются как carry)

Параллельный счетчик:
(разрешаются локальные сигналы, работает быстрее)

VHDL програма для двоичного счетчика 0..f

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.STD_LOGIC_UNSIGNED.all;
    use ieee.std_logic_arith.all;

    entity count4 is
        port (
            clk,reset : in std_logic;
                count: out std_logic_vector(3 downto 0));
    end count4;

    architecture Example of count4 is
        signal count_i: std_logic_vector(3 downto 0);
    begin
        process(clk,reset)
        begin
            if (reset = '1') then
                count_i <= "0000";
            elsif rising_edge(clk) then
                count_i <= count_i + '1';
            end if;
        end process;
        count <= count_i;
    end Example;

Программа на Verilog для счетчика 8-бит:

    module	COUNTER(EN,CLK,RESET,OUT);
        parameter  width = 8;
        input	   CLK,RESET,EN;
        output [width-1:0] OUT;
        reg    [width-1:0] OUT;

        always @(posedge CLK or negedge RESET)
            if (!reset)
                OUT = 8'b0;
            else if (EN)
                OUT = OUT + 1;
    endmodule;

Счетчик считающий в обе стороны:


13.1. ОБРАТНАЯ СВЯЗЬ В СЧЕТЧИКАХ

Возьмем паралельный счетчик из предидущей секции и добавим к нему
обратную связь, что бы по достижении 101 он асинхронно сбрасывался в 0.
(т.е. считать он будет: 000,001,010,011,100,  000...)
Добавим обратную связь

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

Добавим обратную связь, что бы счетчик обновлялся по достижению 0xb
VHDL програма для двоичного счетчика 0..f

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.STD_LOGIC_UNSIGNED.all;
    use ieee.std_logic_arith.all;

    entity count4 is
        port (
            clk,reset : in std_logic;
                  count: out std_logic_vector(3 downto 0));
    end count4;

    architecture Example of count4 is
        signal count_i: std_logic_vector(3 downto 0);
    begin
        process(clk,reset)
        begin
            if (reset = '1') then
                count_i <= "0000";
            elsif rising_edge(clk) then
                count_i <= count_i + '1';
                if count_i = "1011" then
                    count_i <= "0000";
                end if;
            end if;
        end process;
        count <= count_i;
    end Example;

Имплементация счетчика в Xilinx Virtex-II

Пример BCD счетчика

Пример счетчика который может считать в обе стороны

Счетчик вместе с схемами загрузки

Пример счетчика считающего до 6 в коде Грея:

Пример счетчика с предзагрузкой и очисткой

Каскад счетчиков


13.2. ПОСЛЕДОВАТЕЛЬНО-ПАРАЛЕЛЬНЫЙ РЕГИСТР И СЧЕТЧИКИ

THIS SECTION IS UNDER CONSTRUCTION

Последовательно-паралельный реристр

  Кольцевой счетчик

Кольцевой счетчик (Ring counter)

  Счетчик Джонсона


14. УМНОЖИТЕЛЬ

  Умножение

Def
===
    УМНОЖИТЕЛЬ - функциональный узел, который умножает 2 числа.

Что такое умножение:

    a * b = a * a * a * ... * a * a * a
        |                         |
        +-------------------------+
            b раз

Что такое умножение в двоичной системе:

    X * 0 = 0
    X * 1 = X
    X * Y = X AND Y

таким образом умножение в двоичной системе сводится к сдвигу и
сложению:

        10101
        *   10111
    -------------
        10101
           10101
       +      10101
         00000
        10101
    -------------
        111100011

  Типы умножителей

            Умножение    ----------------------------+
             /       |     \                             |
        ПАРАЛЕЛЬНЫЕ УМНОЖИТЕЛИ                    ПОСЛЕДОВАТЕЛЬНЫЙ
         Аппаратный  Табличный  Комбинированный         УМНОЖИТЕЛЬ
         умножитель    метод     метод

Время:	     долго	   быстро    средне                 очень много
Элементы:    много      очень много  относительно мало        мало

  Последовательный умножитель

Микропрограмная реализация последовательного умножителя
        result = 0;
        temp   = Y;
        for i = 0 to N do
        begin
            if (bit(i,X) == 1) then
            begin
                result = result + temp;
            end;
            temp = SHIFT_RIGHT(temp,1);
        end;

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

  Знаковое и беззнаковое умножение

Умножение знаковых и беззнаковых чисел различное:

        ab
       *    cd
    -----------
          00bd          БЕЗЗНАКОВЫЕ
     +	      0ad
          0cb
              ac
    -----------

        ab
       *    cd
    -----------
          SSbd          ЗНАКОВЫЕ
     +	      Sad           (S = знаковое расширение частичного произведения)
          Scb
              ac
    -----------

Обратите внимание:
    младшие N байт произведения (N*N) не зависят от знака
    поэтому в RISC микропроцессорах обычно используют три команды для
    умножения:
         MULL	Multiply Low  		(младшие N бит)
        MULHS	Multiply High Signed    (старшие N бит знаковое *)
        MULHU   Multiply High Unsigned  (старшие N бит беззнаковое *)

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

  Сокращение числа частных произведений

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

    Значение произведения блока может быть вычислено быстрым аппаратным
умножителем или табличным методом.

Умножение в столбик:

        +------+------+
        |  a   |   b  |
       *	+------+------+
            |  c   |   d  |
        +------+------+
 =====================================
        +-------------+
        |      bd     |
        +-------------+
    +--------------+
    |      ad      |
+	+--------------+
    +--------------+
    |      cb      |
    +--------------+
 +--------------+
 |      ac      |
 +--------------+
 =====================================
 +-----------------------------+
 |           Result            |
 +-----------------------------+

  Табличный метод умножения

Табличный метод:

Строится ПЗУ содержащее таблицу умножения.
0 и 1 - особые случаи, их можно обработать аппаратно отдельно.
Пример такой таблицы для умножителя 3x3 = > 6
(данные в таблице представленны в 16-ричной системе счистления):
Можно хранить не всю таблицу а ее половину т.к. она симметрична.

      *|2  3  4  5  6  7
      -+-----------------
      2|04 06 08 0A 0C 0E
      3|   09 0C 0F 12 15
      4|      10 14 18 1C
      5|         19 1E 23
      6|            24 2A
      7|               31

Время работы для 4x4 = время дешифратора(8бит) + L (транзистор)
             = (инвертор + 3 * И) + L (транзистор) = 5L

  Методы быстрого аппаратного умножения

    Матричный (n-частичных произведений суммируются в n-каскадах)
    Бута      (уменьшенно количество частных произведений)
    Уолеса    (параллельное сложение частных произведений)
    NMM       (умножение без сложения)


14.1. СЕМЕЙСТВО МЕТОДОВ БУТА

Метод Бута:

Идеи лежащие в основе семейства методов:

Общая идея:
    Очевидно что:

        2^m + 2^(2m-1) + ... + 2^k = 2^(m+1) - 2^k

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

    то мы сможем ее заменить на
                    _
        00100000100

    уменьшив таким образом число частных произведений.

Метод Бута:
    Берем множитель и анализируем ему 2 бита
    (0,1) ------- > (-1, 0, 1)
    (Для самого младшего разряда считаем что более младший разряд равен 0)

    ------------------------------------------------------------------
    B{i}B{i-1}	Что значит			Что делаем
    ------------------------------------------------------------------
      1  0		Начало цепочки из единиц	вычитаем        -M
      0  1		Завершение цепочки из единиц    прибавляем      +M
      0  0		нет цепочки единиц		ничего не делаем
      1  1		внутри цепочки единиц		ничего не делаем
    ------------------------------------------------------------------

Модифицированный алгоритм Бута (MBR):
    Анализируются сразу 3 разряда:
    (0, 1) --- > (-2, -1, 0, -1, 2)
    ------------------------------------------------------------------
    B{i+1}B{i}B{i-1} что значит			что делаем
    ------------------------------------------------------------------
     0     0     0	нет цепочки единиц		ничего не делаем
     0     0     1	завершение цепочки из единиц	+M
     0     1     0	одиноко стоящая единица		+M
     0     1     1	завершение цепочки единиц	+2M
     1     0     0  начало цепочки из единиц	-2M
     1     0     1	начало+завершение		-M  (-2M +M)
     1     1     0	начало цепочки из единиц	-M
     1     1     1  внутри цепочки единиц		ничего не делаем
    ------------------------------------------------------------------

Алгоритм Лемана:
    Если две группы нулей разделены одной единицей то вместо вычитания
    в позиции k и сложения в позиции (k+1) мы можем сделать сложение
    в позиции k
                  k
              |
        000000100000
             |
            k+1

    Если две группы единиц разделены нулем то вместо сложения в позиции
    k и вычитания в позиции (k+1) можно сделать вычитание в позиции k

                 k
             |
        111110111111
            |
           k+1

Реализации:
    умножение сразу на 2 бита.
    минимизировать количество частных произведений

    P = A * B = (a{n-1}*2^(n-1) + ... + a{0}*2^0) *
            (b{n-1}*2^(n-1) + ... + b{0}*2^0)     =
             A*b{n-1}*2^(n-1)+ ... + A*b{0}*2^0

    Заметим
        b{i}*2^i = b{i}*2^(i+1) - 2*b{i}*2^(i-1)
    Частные произведения после подстановки будут иметь вид
        A * (-2*b{i+1} + b{i} + b{i-1}) * 2^i

Алгоритм Бута:

Простое умножение (для примера):

Простой умножитель Бута на 2 бита (MBR):

Схема ячейки в умножителе Бута

Топология ячейки в умножителе Бута

Умножитель Бута на 3 бита:


14.2. МАТРИЧНЫЕ УМНОЖИТЕЛИ

     C  S
         |  |
     V  V
    +-----+
    | CPA | 	Carry Propagation Adder
    +-----+		Медленный T = ~ n*3L, где n-число разрядов
       |
       V
       S

Простой матричный метод:

         A  B     C  D     E F
         |  |     |  |     | |
     V  V     V  V     V V
    +-----+  +-----+  +-----+
    | CPA |  | CPA |  | CPA |
    +-----+  +-----+  +-----+
       |	      |    |
       |          V    V
            |	     +------+
       |	     | CPA  |
       |	     +------+
       |	       |
       +----+  +---+
        |  |
        V  V
          +------+
          | CPA  |
          +------+
         |
         V

Время работы T = 9 nL

Умножение 5x5:

  Простой матричный умножитель

Простой матричный умножитель:

                     n-1  n-1
                     ---  ---
                     \    \
    P = A * B =  /    /    A{i}B{j}*2^(i+j)
                 ---  ---
                     i=0  j=0

            A{n-1} ............ A{0}
            B{n-1} ............ B{0}
      ------------------------------------------
                A{n-1}B{0}......A{0}B{0}
               ....................
                      ....................
                     ....................
            ...................
           ..................
                 ..................
            A{n-1}B{n-1}..A{0}B{n-1}
      ------------------------------------------
     P{2n-1}  P{2n-2} ...................   P{0}

Простой матричный умножитель Брауна
(только положительные числа):
(использованы также полусумматоры, потому что верхняя строка все равно
складывает только 2 числа, а не 3 как остальные).

Беззнаковый простой матричный умножитель:

Число в дополнительном коде можно представить в виде:

                               n-2
                   ---
                           \
    X = -X{n-1}*2^(n-1) +  /   X{i}*(2^i)
                           ---
                   i=0

Поэтому если мы перемножим два числа в таком представлении и заменим у членов
знак минус на инверсию (для однобитового числа это одно и то же) то получим:

    P = A * B = A{n-1}B{n-1}*2^(2n-2)  +

                    n-2  n-2
                ---  ---
            \	 \
         +  /    /    A{i}B{j}*2^(i+j) +
            ---  ---
            i=0  j=0

            n-2
            ---
            \   ___________
         +  /   A{i}*B{n-1}*2^(i+n-1)  +
            ---
            i=0

            n-2
            ---
            \   ___________
         +  /   A{n-1}*B{j}*2^(j+n-1) +
                    ---
                    j=0

         + 2^n + 2^(2n-1)

Матричный умножитель в дополнительном коде:

Знаковый простой матричный умножитель:

  Умножитель Бо-Вули

Умножитель Бо-Вули
(Baugh Wooley)

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

                               ______   ______
    P = A * B = -(2^(2n-1)) + (A{n-1} + B{n-1} + A{n-1}B{n-1})*2^(2n-2) +

            n-2  n-2
                ---  ---
                    \    \
          + /    /   A{i}B{j}*2^(i+j) +
            ---  ---
            i=0  j=0

            n-2
            ---
                    \   ____
          + /   A{i}B{n-1}*2^(i+n-1)  +
            ---
            i=0

            n-2
            ---
            \          ____
          + /    A{n-1}B{j}*2^(j+n-1)  +
            ---
            j=0

          + (A{n-1} + B{n-1})*2^(n-1)

Умножитель Бо-Вули:

  Умножитель Пезариса

Умножитель Пезариса

(Pezaris)
Тоже матричный, но использует сумматоры четырех различных типов

Элементы применяемые в умножителе Пезариса:

Умножитель Пезариса:

Двухсекционный умножитель:

Трехсекционный умножитель:


14.3. ДРЕВОВИДНЫЕ УМНОЖИТЕЛИ

Древовидные методы

Для сложения используют два вида базовых сумматоров CPA и CSA:

         A B D
         | | |
     V V V
    +------+
    | CSA  |	Carry-Save Adder   (A+B+D = C + S)
    +------+	Быстрый  T = ~ 3L
      |  |  	(он считает быстро сумму и перенос для
      V  V		 каждого разряда, но не переносит в следующий)
      C  S

Для сложения CPA сумматор нужен только в конце.
Предположим что нам надо сложить 6 частных произведений:

  Метод Уолеса

Метод Уолеса:

Умножитель Уолеса:

     A B C      D E F
         | | |      | | |
     V V V      V V V
    +------+  +------+
    | CSA  |  | CSA  |
    +------+  +------+
      |  |	     | |
      |  +-----+ | |
      |	   | | |
      |	   V V V
          |	  +------+
      |	  | CSA  |
      |	  +------+
      | 	     | |
      +--------+ | |
           | | |
           V V V
              +------+
          | CSA  |
          +------+
            | |
            V V
          +------+
          | CPA  |
          +------+
             |
             V

Время работы T = 9L + 3nL

Деревья Уолисса:
Дерево Уолесса для 3:

Дерево Уолесса для 7:

Дерево Уолесса для 15:


14.4. УМНОЖЕНИЕ БЕЗ СЛОЖЕНИЯ (NMM)

NMM Метод

    NMM - (Nonadditive Multiply Module)
          (умножение без сложения)

         +-----+
     A0..A3 -| NMM |- P0..P7
     B0..B3 -|     |
         +-----+

          A3   A2   A1   A0
       *     B3   B2   B1   B0
      ------------------------
           A3B0 A2B0 A1B0 A0B0
+         A3B1 A2B1 A1B1 A0B1
     A3B2 A2B2 A1B2 A0B2
A3B3 A2B3 A1B3 A0B3
-----------------------------------
P7P6 P5   P4   P3   P2   P1   P0

NMM 4x2 умножитель:

                        A3B0 0         A2B0 0         A1B0 0       A0B0
                 |   |          |   |          |   |         |
                         V   V          V   V          V   V         |
                +------+       +------+       +-----+        |
                | CSA  |<-A2B1 | CSA  |<-A1B1 | CSA |<-A0B1  |
                +------+       +------+       +-----+        |
                 |C |S          |C |S          |C |S         |
           A3B1	+--------+  | +---------+  | +---------+  |          |
                 |	|	    | |		   | |            |          |
            V   V	    V V		   V V            |          |
          +------+	 +------+       +------+          |          |
          |  CSA |<-A2B2 | CSA  |<-A1B2 | CSA  |<-A0B2    |          |
          +------+       +------+       +------+          |          |
               |C |S          |C |S          |C  |S           |          |
    A3B2 +-----+  | +---------+  | +---------+   |            |          |
     |   |        | |            | |             |            |          |
     V   V	      V V            V V             |            |          |
    +-----+   +------+       +------+            |            |          |
 A2B3 ->| CSA |   | CSA  |<-A1B3 | CSA  |<-A0B3      |            |          |
    +-----+   +------+       +------+            |            V          V
     |C |S      |C |S          |C |		     |            P1        P0
A3B3 +---+  |	 +--+  +-+   +-----+  |              |
 |   |      |    |       |   |        |              |
 V   V      V    V       V   V        |              |
+-----+    +------+     +------+      |              |
| CSA |<-+ |  CSA |<-+  | CSA  |<- 0  |              |
+-----+	 | +------+  |  +------+      |              |
 |C |S   |  |C |S    |   |C |S        |              |
 |  |    +--+  |     +---+  |         |              |
 |  |          |            |         |              |
 V  V          V            V         V              V
P7  P6        P5            P4        P3             P2

Время работы T = 19L

Пример реализации Двухбитного умножителя (на базе NMM)
(правда особой разницы на 2х битах мы не увидем).

      a1    a0
      *   b1    b0
   ----------------
+       a1b0  a0b0
  a1b1  a0b1
  -----------------
                ^
        |
        +--- не тянет за собой перенос

Результат: AND элементы и каскад полусумматоров.

Иерархия NMM умножителей:

Ячейка NMM умножителя:

    library	ieee;
    use	ieee.std_logic_1164.all;

    entity nmm_cell is
        port(
            a,b,cin,sin : in std_logic;
                  sout, cout  : out std_logic);
    end nmm_cell;

    architecture cell of nmm_cell is
        signal	x : std_logic;
        component full_adder is
            port (
                a,b,cin : in std_logic;
                      s, cout : out std_logic);
        end component;

    begin
        fa1 : full_adder
            port map(sin,x,cin,sout,cout);
        x <= a and b;
    end cell;

NMM умножитель (любого размера):

    library	ieee;
    use	ieee.std_logic_1164.all;

    entity nmm is
        generic(n : natural range 32 downto 2);
        port(
            a,b : in std_logic_vector(N-1 downto 0);
                 p   : out std_logic_vector(2*N-1 downto 0));
    end nmm;

    architecture nmmi of nmm is
        type sum_array   is array(N downto 0, N downto 0) of std_logic;
        type carry_array is array(N-1 downto 0, N downto 0) of std_logic;

        signal sum: sum_array;
        signal carry : carry_array;

        component nmm_cell is
            port(
                a,b,cin,sin : in std_logic;
                     sout, cout  : out std_logic);
        end component;

    begin
        row :	for i in N-1 downto 0 generate
            col:	for j in N-1 downto 0 generate
                            ex_cell: nmm_cell
                    port map(a(i),b(j),carry(i,j),sum(i,j+1),
                         sum(i+1,j),carry(i,j+1));
                top_row: if i = 0 generate
                    sum(i,j+1) <= '0';
                end generate;

                bottom_row: if i = N-1 generate
                    p(N+j) <= sum(i+1,j+1);
                end generate;

                left_col: if j = N - 1 generate
                    sum(i+1,j+1) <= carry(i,j+1);
                end generate;

                right_col: if j = 0 generate
                    carry(i,j) <= '0';
                    p(i) <= sum(i+1,j);
                end generate;

            end generate;
        end generate;
    end nmmi;

Результат моделирования NMM умножителя 3x3 (фрагмент):

Пример умножителя 8x8 на основе NMM 4x4 и дерева Уолиса:

    +------------+	+-----------+  +-----------+  +-----------+
    |  Ah * Bh   |  |  Al * Bh  |  | Ah * Bl   |  |  Al * Bl  |
    +------------+  +-----------+  +-----------+  +-----------+
       |H    |L        |H      |L    |H |L         |H    |L
       |     |    +----+       |     |  |          |     |
       |     |    |   +--------=-----+  | +--------+     V
       |     |    |   |        |        | |             R3..0
       |	 V    V   V        V        V V
       |	+-----------+	  +------------+
       |	|   CSA  1  |     |   CSA   2  |
       |	+-----------+	  +------------+
       |      |C12.9 |S11.8     |S7..5  |C8..5
       |      |	 |          |       |
       +------=------O----------+       |
    H15..12       |      |                  |
          +------=--------O---------+
             |        |
             V        V
            +---------------+
            |     CPA       |
            +---------------+
                |
                    V
                 R15..4

В CPA складываются:  1) H15..12, S11..8, S7..5
             2) C12..9 , C8..5

Время работы T = Tnmm + Tcsa + Tcpa(n=12)
         T = 19L  + 3L   + 12 * 3L  = 58L


14.5. УМНОЖИТЕЛИ: ИТОГИ

Сравнение методов умножения
(В таблице:  число каскадов/число транзисторов)

Method		8	16	32	64	128
Матричный	29 	61  	125 	253  	509   		~n
        528     2336    9792    40064   162048          ~n**2

Бута-Уолеса	22 	24  	30  	34   	40    		~n
        815     2939    9965    37423   142335          ~n**2

  Что происходит в реальном Мире

Метод Бута:
        4x4		4x4		8x8		8x8
Умножение       умножений	сложений	умножений	сложений
8x8		4		3		1		0
16x16		16		15		4		3
32x32		64		63		16		15

Число тактов на умножение в x86:

MUL		8x8		16x16		32x32
8086		70-83		118-143
286		13-16		21-24
386		9-14		9-22		9-38
486		13-18		13-26		13-42
Pentium		11		11		11

386 (Eary out algorithm):
    if (множитель != 0) then
        clocks = MAX(3,округление(log2(множитель))+6)
    else
        clocks = 9
    endif;

ДЕЛАЙТЕ ВЫВОДЫ САМИ.


15. ДЕЛЕНИЕ В CPU

    В отличии от умножения деление не так хорошо подвергается
оптимизации (в частности многие RISC процессоры вообще не имеют
команды деления).

Базовый алгоримтм для деления:

Делили ли Вы в школе в столбик.
В общем то деление это сравнения и вычитание.

    A = B * (C0*2^(m-n) + C1*2^(m-n-1) + .. + Cm-n*2^0) + ## частное
        R0*2^0 + .. + Rn*2^N			      ## остаток

Алгоритм:
    +---------------+
    |    Ai         |    n битов
    +---------------+  	    		k-я итерация
        +-------+
        |  B    |	     m битов
    <-->+-------+
      k битов

0) В начале B0 = B сдвинутое так чтобы его старший бит был MSB.

1) Вычисляем Ai-Bi  (в смысле B на k-й позиции от начала A)
    Если перенос то
        Ai < Bi      (Bi = B * 2^(m-n-k))
         и
        Cj при 2^(m-n-k) = 0
        Ai+1 = Ai
    Eсли нет переноса то
        Cj при 2^(m-n-k) = 1
        Ai+1 = Ai - Bi
    Bi+1 = Bi shift left 1
    И делаем так пока не достигнем итерации (n-m)

    ----------------------------
    Ai-Bi	  Next	  1bit of
    CF        Ai      Result
    ----------------------------
    1	  Ai	  0
    0	  Ai-B	  1
    ----------------------------

Таким образом схема для деления выглядет как:

                    ^
            | паралельный выход для остатка
        CF	+---------+
    +-----+-----| Adder   |<--- Паралельный вход для делимого
    |	  |	+---------+
    |	  |	^     ^  ^
    |	  |     |     |  |
    |	  V	|A/S  |  +------------+
    |  +--------+   +------------+    |
    |  | логика	|   |конвертер в | +------+
    |  +--------+   |обратный код| |Buffer|
    |               +------------+ +------+
    |		           ^          ^
    |                      |          |
    |                      | +--------+
    |			   | |
    |		+-------------+
    |           | Shift Reg   |<--- паралельный вход для делителя
    |		+-------------+
    |       +------------+
    +------>|  Shift Reg |
        +------------+
               | паралельный выход для результата
           V

Оптимизация деления:

    Можно ли убыстрить деление в столбик?
    Можно если паралельно обрабатывать не по 1 биту результата
    а по 2.

    Идея:
        Вычитаем  Ai-Bi
                  Ai-2Bi	(2Bi = Bi + Bi)
              Ai-3Bi	(3Bi = Bi + Bi + Bi)

    ------------------------------------------
    Ai-Bi	Ai-2Bi	Ai-3Bi	   Next	  2bit of
    CF       CF      CF        Ai     Result
    ------------------------------------------
    0	0	0	Ai-3B	   11
    0	0	1	Ai-2B	   10
    0	1	1	Ai-B	   01
    1	1	1	Ai	   00
    ------------------------------------------

Современные матричные методы деления:

  Restore Division

Restore Division в смысле что остаток остается.

1. Частичный остаток = старшие разряды делимого
2. Частичный остаток << 1 бит
   В младший разряд идет очередная цифра частного
3. Из сдвинутого остатка вычитается делитель, анализируется знак вычитания
4. Следущая цифра частного равна 1, если результат положительный.
   Следущая цифра частного равна 0, если результат отрицательный,
   при этом делитель прибавляется обратно (restore).

Действия со знаком:
    -------------------------------------------------
    Знак остатка	Знак делителя		Действие
    -------------------------------------------------
    +		+			-делитель
    +		-			+делитель
    -		+			+делитель
    -		-			-делитель
    -------------------------------------------------

4x4 Restore array division:

Restore array cell:

SC Cell:

    -----------------
    q r d Ci | Co S
    ---------+-------
    0 0 0 0  |  0 0
    0 0 0 1  |  0 0
    0 0 1 0  |  0 0
    0 0 1 1  |  1 0
        0 1 0 0  |  0 1
    0 1 0 1  |  1 1
    0 1 1 0  |  1 1
    0 1 1 1  |  1 1
    1 0 0 0  |  0 0
    1 0 0 1  |  0 1
    1 0 1 0  |  0 1
    1 0 1 1  |  1 0
    1 1 0 0  |  0 1
    1 1 0 1  |  1 0
    1 1 1 0  |  1 0
    1 1 1 1  |  1 1
    -----------------

  Non-Restore Division

1. Частичный остаток = старшие разряды делимого
2. Частичный остаток << 1 бит
   В младший разряд идет очередная цифра частного
3. Из остатка вычитается делитель, если остаток положительный
   к остатку прибавляется делитель, елси остаток отрицательный
4. Следущая цифра частного равна 1, если результат положительный.
   Следущая цифра частного равна 0, если результат отрицательный

4x4 Non-restore array division:

4x4 Non-restore array cell:

AS-Cell:
    -------------------
      q r d Ci | Co S
    -----------+-------
     -1 0 0 0  |  0 0
     -1 0 0 1  |  0 1
     -1 0 1 0  |  0 1
     -1 0 1 1  |  1 0
     -1 1 0 0  |  0 1
     -1 1 0 1  |  1 0
     -1 1 1 0  |  1 0
     -1 1 1 1  |  1 1
      1 0 0 0  |  0 1
      1 0 0 1  |  1 0
      1 0 1 0  |  0 0
      1 0 1 1  |  0 1
      1 1 0 0  |  1 0
      1 1 0 1  |  1 1
      1 1 1 0  |  0 1
      1 1 1 1  |  1 0
    -------------------

  SRT-Division

SRT (Sweeney, Robertson and Tocher)
независимо друг от друга

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

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

для i-й итерации:

       |  1, if 2R{i-1} > = D
Q{i} = |  0, if -D <= 2R{i-1} < D
       | -1, if 2R{i-1} < -D

R{i}  = 2R{i-1} - Q{i}*D

Tail-Cell:

    ------------------
     q d0 r0 | s1 s0
    ---------+--------
    -1  0 -1 |  0 -1
    -1  1 -1 |  0  0
    -1  0  0 |  0  0
    -1  1  0 |  1 -1
    -1  0 +1 |  1 -1
    -1  1 +1 |  1  0
     0  0 -1 |  0 -1
     0  1 -1 |  0 -1
     0  0  0 |  0  0
     0  1  0 |  0  0
     0  0 +1 |  1 -1
     0  1 +1 |  1 -1
    +1  0 -1 |  0  0
    +1  1 -1 |  0 -1
    +1  0  0 |  1 -1
    +1  1  0 |  0  0
    +1  0 +1 |  1  0
    +1  1 +1 |  1 -1
    ------------------

Head-Cell:

    -----------------------
    r2 r1 r0 | s2 s1 s0  q
    ---------+-------------
    +1 +1 +1 | +1 +1 -1 +1
    +1 +1  0 | +1  0  0 +1
    +1 +1 -1 | +1  0 -1 +1
    +1  0 +1 | +1  0 -1 +1
    +1  0  0 |  0 +1  0 +1
    +1  0 -1 |  0 +1 -1 +1
    +1 -1 +1 |  0 +1 -1 +1
    +1 -1  0 |  0  0  0 +1
    +1 -1 -1 |  0  0 -1 +1
     0 +1 +1 |  0 +1 -1 +1
     0 +1  0 |  0  0  0 +1
         0 +1 -1 |  0  0 -1 +1
     0  0 +1 |  0  0 -1 +1
     0  0  0 |  0  0  0  0
     0  0 -1 |  0  0  0 -1
     0 -1 +1 |  0  0  0 -1
     0 -1  0 |  0  0 -1 -1
     0 -1 -1 |  0 -1  0 -1
    -1 +1 +1 |  0  0  0 -1
    -1 +1  0 |  0  0 -1 -1
    -1 +1 -1 |  0 -1  0 -1
    -1  0 +1 |  0 -1  0 -1
    -1  0  0 |  0 -1 -1 -1
    -1  0 -1 | -1  0  0 -1
    -1 -1 +1 | -1  0  0 -1
    -1 -1  0 | -1  0 -1 -1
    -1 -1 -1 | -1 -1  0 -1
    -----------------------


15.1. АППАРАТНОЕ ВЫЧИСЛЕНИЕ КВАДРАТНОГО КОРНЯ

  Квадратный корень

Restore Square Root:

Non-Restore Square Root:

  Объединеный Div/Root

Блок для вычисления квадратного корня может быть объединен с делителем:

TRS Cell:

    ------------------
     q si ci | so co
    ---------+--------
    +1  0  0 |  0  0
    +1  0  1 |  0  0
    +1  1  0 |  1  0
    +1  1  1 |  1  0
     0  0  0 |  0  0
     0  0  1 |  0  1
     0  1  0 |  1  0
     0  1  1 |  1  1
    -1  0  0 |  0  0
    -1  0  1 |  1  0
    -1  1  0 |  1  0
    -1  1  1 |  0  0
    ------------------


16. КОНТРОЛЬ ОШИБОК И КОРРЕКТИРУЮЩИЕ КОДЫ

        Коды исправляющие ошибку
            /          \
           блочные         сверточные
            коды           коды
          /   \
       разделимые  неразделимые
       /     \
    линейные    нелинейные
     коды       коды
      |
   циклические
    коды

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

Разделимые коды - биты данных идут отдельно в том виде как они заданны
           Еще их называют систематическими
Неразделимые коды - нет битов данных в явном виде


16.1. КОНТРОЛЬ ЧЕТНОСТИ

Простая идея как обнаружить единичную ошибку (да и вообще нечетное
число ошибок): посчитать четность.

Такие коды называются SPC (Single Parity Check).

    +-+-+-+-+-+-+-+-+    +-+
    | | | | | | | | |    |B|
    +-+-+-+-+-+-+-+-+    +-+
          BYTE	     CONTROL BIT

    B = A0 (+) A1 (+) A2 (+) A3 (+) A4 (+) A5 (+) A6 (+) A7

    Если четность не совпадает - то обнаружена ошибка.
    (Этот метод используется в RS-232-C [COM port]).

Пример реализации:

Порождающая матрица для SPC кода (4,3)

    | 1  0  0  1 |
    | 0  1  0  1 |
    | 0  0  1  1 |

  Data	[1]| 1  0  0  1 |
------ )[2]| 0  1  0  1 |
    [3]| 0  0  1  1 |
        ------------------
        [1][2][3][4]
          |
          V
         Code

    c1 = d1
    c2 = d2
    c3 = d3				Код систематический
    c4 = d1 (+) d2 (+) d3

Простая идея как исправить ошибку.

Если нам надо переслать данные мы их пересылаем 2*N + 1 раз.
Это позволит исправить до N ошибок включительно.
Нам в этом может помочь мажоритарный элемент.

Но вот только кто на это согласится?. Пересылать так много.


16.1.1. КОД ПОВТОРЕНИЕ

Код повторение - данные повторяются несколько раз

Например код повторение (3,1,3)

Порождающая матрица:

    | 1 1 1 |

Проверочная матрица:

    | 1 1 0 |
    | 1 0 1 |

Синдромы:

    ------------------------------------------
    синдром		значение0	значение1
    ------------------------------------------
    00		000		111
    11		100		011
    10		010		101
    01		001		110
    ------------------------------------------

Кормим проверочной матрице значение кода получаем - синдром
Для синдрома выбираем лидера класса (того кто содержит меньше всего единичек)
Коррекция - складывание кода (в смысле XOR) c лидером класса для соответсвующего
синдрома.


16.2. КОМПОЗИЦИОННЫЕ КОДЫ

Композиционные коды (product code) строятся так:
из информационных битов строится двумерная решетка
и к ней добавляются проверочные биты как к столбцам так и к строкам

    +------------+-+
    |DDDDDDDDDDDD|P|
    |DDDDDDDDDDDD|P|
    |DDDDDDDDDDDD|P| 		D - данные
    |DDDDDDDDDDDD|P|		P - четность
    +------------+-+
    |PPPPPPPPPPPP|P|
    +------------+-+

строки  код Crow с расстоянием Drow
столбцы код Ccol с дистанцией  Dcol

Минимальная дистанция = Drow * Dcol
(поэтому код называется product code - код произведение)

Если один символ проверки на четность в каждом столбце/строке
то дистанция = Drow * Dcol = 2 * 2 = 4

Т.е. код гарантированно обнаруживает 1,2 или 3 ошибки.
Или обнаруживает 1,2 ошибки и исправляет одну.

4 ошибки по углам уже не обнаруживаются:

    +------------+-+
    |            | |
    |  X     X   | |
    |            | |
    |  X     X   | |
    |	     | |
    +------------+-+
    |            | |
    +------------+-+

В качестве примера будем использовать блок 3x3 (a1..a9):

    -----------------
    a1  a2  a3  | b1
    a4  a5  a6  | b2
    a7  a8  a9  | b3
    ------------+---
    b4  b5  b6  | b7
    ----------------

    b1 = a1 (+) a2 (+) a3
    b2 = a4 (+) a5 (+) a6
    b3 = a7 (+) a8 (+) a9
    b4 = a1 (+) a4 (+) a7
    b5 = a2 (+) a5 (+) a8
    b6 = a3 (+) a6 (+) a9

    b7 = XOR(a1,..a9,b1..b6)

При длинне данных X**2, длинна проверок простого композиционного кода (2X+1)

    X	DATA	CODE	CODE %
    3	9	7	78%
    10	100	21	21%
    100	10000	201	2%

  Одиночные ошибки

# - место ошибки
* - место нарушения четности

    -----------------
    a1  a2  a3  | b1
    a4  a5  a6  | b2         		ОШИБКА В ДАННЫХ
    a7  a8# a9  | b3*  <-- здесь            A8
    ------------+---
    b4  b5* b6  | b7*  ошибка
    ----------------
         ^
         |
        здесь

    Строка + Столбец + Ошибка => ошибка в данных

    -----------------
    a1  a2  a3  | b1
    a4  a5  a6  | b2                	ОШИБКА В КОДЕ
    a7  a8  a9  | b3			B4
    ------------+---
    b4# b5  b6  | b7*  ошибка
    ----------------
        ^
    |
    здесь

    Столбец + Ошибка => ошибка в коде столбца

    -----------------
    a1  a2  a3  | b1         		ОШИБКА В КОДЕ
    a4  a5  a6  | b2                        B7
    a7  a8  a9  | b3
    ------------+---
    b4  b5  b6  | b7#  ошибка
    ----------------

    Ошибка => ошибка в b7

  Двойные ошибки

В одном столбце/строке:

    -----------------
    a1  a2  a3  | b1
    a4# a5  a6  | b2*  <- здесь
    a7# a8  a9  | b3*  <- здесь
    ------------+---
    b4  b5  b6  | b7
    ----------------

Двойная ошибка обнаружена, но исправить ее не можем,
т.к. не знаем столбец.

В разных строках:

    -----------------
    a1# a2  a3  | b1*  <---
    a4  a5# a6  | b2*  <---
    a7  a8  a9  | b3
    ------------+---
    b4* b5* b6  | b7
    ----------------
    ^   ^
    |   |

Двойная ошибка обнаружена, можем ее исправить.

    -----------------
    a1  a2  a3  | b1
    a4  a5  a6  | b2#  <---
    a7  a8  a9  | b3
    ------------+---
    b4# b5  b6  | b7
    ----------------
     ^
     |

    b7 ошибки не имеет => двойная ошибка.

    -----------------
    a1  a2  a3# | b1*
    a4  a5  a6  | b2
    a7  a8  a9  | b3
    ------------+---
    b4  b5  b6* | b7#  -> b7 виден как нет ошибки => двойная ошибка.
    ----------------

Композиционные коды могут строится и на основе строчных/столбцовых кодов
с другими длиннами дистанции. Тогда они смогут исправлять/детектировать
большее число ошибок.

    +------------+---+
    |            |   |
    |            |   |
    |            |   |
    |            |   |
    +------------+---+
    |            |   |
        |            |   |
    +------------+---+

Двумерные композиционные коды - это не предел.
Можно строить product коды и с большей размерностью.

HoVer code


16.3. КОД ХЭММИНГА

Hamming

Построение Кода Хэмминга:

Основная идея кодов Хэмминга - что бы исправить ошибку надо как
минимум иметь столько проверочных бит что бы можно было адрессовать
все биты данных + проверочные биты.

bit	  9   8   7   6   5   4   3   2   1
    +---+---+---+---+---+---+---+---+---+      +---+
    |   |XXX|   |   |   |XXX|   |XXX|XXX|      |ZZZ|
    +---+---+---+---+---+---+---+---+---+      +---+
         p4  a3  a2  a1  p3  a0  p2  p1         p

    1. Контрольные разряды занимают места с позицией 2**N (N=0..)
    2. В свободные места кладутся данные
    3. p1 покрывает разряды ai с позициями XXXXX1 (1,3,5,7,9...)
       p2 покрывает разряды ai с позициями XXXX1X (2,3,6,7,10,11,..)
       p3 покрывает разряды ai с позициями XXX1XX (4,5,6,7,12,13,14,15,..)
       (имеются в виду разряды в этой сетке, смотрятся только
        разряды данных)

    4. Еще иногда есть p которое общее для всей кодовой комбинации
       p = a0 (+) ... (+) aN (+) p1 (+) ... (+) pM

    Код Хэмминга X/Y - означает:
        X/Y =  Общая длинна/Число разрядов данных.

    p1 p2 d1 p3 d2 d3 d4 p4 d5 d6 d7 d8 d9 d10 d11 p5 d12 d13 d14 d15 d16 d17 d18
p1  X     X     X     X     X     X     X      X      X       X       X        X
p2     X  X        X  X        X  X        X   X          X   X            X   X
p3           X  X  X  X              X  X  X   X                   X  X    X   X
p4                       X  X  X  X  X  X  X   X
p5                                                 X  X   X   X    X  X    X   X2

  Код Хэмминга 7/4 (8/4)

    Код Хэмминга 7/4 (8/4)

    7/4 - это без p  (distance = 3)  исправляет одиночные
    8/4 - это с p	 (distance = 4)	 исправляет одиночные +
                     обнаруживает двойные

    -----------------------------------------------------------
    p	a3	a2	a1	p3	a0	p2	p1
    ----------------------------------------------------------- -+
    0	0	0	0	0	0	0	0    |
    1	0	0	0	0	1	1	1    |
    1	0	0	1	1	0	0	1    |
    0	0	0	1	1	1	1	0    |
    1	0	1	0	1	0	1	0    |
    0	0	1	0	1	1	0	1    |
    0	0	1	1	0	0	1	1    |
    1	0	1	1	0	1	0	0    +
    0	1	0	0	1	0	1	1    + симметрия
    1	1	0	0	1	1	0	0    |
    1	1	0	1	0	0	1	0    |
    0	1	0	1	0	1	0	1    |
    1	1	1	0	0	0	0	1    |
    0	1	1	0	0	1	1	0    |
    0	1	1	1	1	0	0	0    |
    1	1	1	1	1	1	1	1    |
    ----------------------------------------------------------- -+

    p1 = a0 (+) a1 (+) a3
    p2 = a0 (+) a2 (+) a3
    p3 = a1 (+) a2 (+) a3

Наглядный пример кода хэмминга:

Это 4 бита данных которые надо защищать:

Добавляем биты четности так, что бы в каждой окружности было четное
число единичных битов.
(Это код Хэмминга 7/4)

Синдромы одиночной ошибки:

Добавляем теперь бит общей четности получаем код Хэмминга 8/4:

Пример кодера в код Хэмминга 8/4:

Пример кодера в код Хэмминга 8/4:

    library	ieee;
    use	IEEE.std_logic_1164.ALL;

    ENTITY hamenc IS
        port(
            datain : IN BIT_VECTOR(0 TO 3); --d0 d1 d2 d3
            hamout : OUT BIT_VECTOR(0 TO 7)--d0 d1 d2 d3 p0 p1 p2 p4
            );
    END hamenc;

    ARCHITECTURE arch OF hamenc IS
        signal	p0, p1, p2, p4 : BIT; --check bits
    BEGIN
        --generate check bits
        p0 <= (datain(0) XOR datain(1)) XOR datain(2);
        p1 <= (datain(0) XOR datain(1)) XOR datain(3);
        p2 <= (datain(0) XOR datain(2)) XOR datain(3);
        p4 <= (datain(1) XOR datain(2)) XOR datain(3);

        --connect up outputs
        hamout(4 TO 7) <= (p0, p1, p2, p4);
        hamout(0 TO 3) <= datain(0 TO 3);
    END arch;

Декодирование:

Исправление одиночных ошибок:

    p  p3  p2  p1
    -  -   -   -	нет ошибки
    E  -   -   -	ошибка в p
    E  -   -   E    ошибка в p1
    E  -   E   -	ошибка в p2
    E  -   E   E    ошибка в a0
    E  E   -   -	ошибка в p3
    E  E   -   E    ошибка в a1
    E  E   E   -	ошибка в a2
    E  E   E   E	ошибка в a3
    -  X   X   X	двойная ошибка  (XXX != ---)

    (- нет ошибки, E - ошибка)

Пример декодера с исправлением одиночных ошибок
из кода Хэмминга 8/4.

Пример декодера из кода Хэмминга 8/4:

    library	ieee;
    use	IEEE.std_logic_1164.ALL;

    ENTITY hamdec IS
        PORT(
            hamin : IN BIT_VECTOR(0 TO 7); --d0 d1 d2 d3 p0 p1 p2 p4
            dataout : OUT BIT_VECTOR(0 TO 3); --d0 d1 d2 d3
            sec, ded, ne : OUT BIT); --diagnostic outputs
    END hamdec;

    ARCHITECTURE arch OF hamdec IS
    BEGIN
        PROCESS(hamin)
            VARIABLE syndrome : BIT_VECTOR(3 DOWNTO 0);
        BEGIN
            --generate syndrome bits
            syndrome(0) := (((((((hamin(0) XOR hamin(1)) XOR hamin(2)) XOR hamin(3))
                    XOR hamin(4)) XOR hamin(5)) XOR hamin(6)) XOR hamin(7));
            syndrome(1) := (((hamin(0) XOR hamin(1)) XOR hamin(3)) XOR hamin(5));
            syndrome(2) := (((hamin(0) XOR hamin(2)) XOR hamin(3)) XOR hamin(6));
            syndrome(3) := (((hamin(1) XOR hamin(2)) XOR hamin(3)) XOR hamin(7));
            IF (syndrome = "0000") THEN --no errors
                ne <= '1';
                ded <= '0';
                sec <= '0';
                dataout(0 TO 3) <= hamin(0 TO 3);
            ELSIF (syndrome(0) = '1') THEN --single bit error
                ne <= '0';
                ded <= '0';
                sec <= '1';
                CASE syndrome(3 DOWNTO 1) IS
                WHEN "000"|"001"|"010"|"100" =>
                    dataout(0 TO 3) <= hamin(0 TO 3); -- parity errors
                WHEN "011" => dataout(0) <= NOT hamin(0);
                    dataout(1 TO 3) <= hamin(1 TO 3);
                WHEN "101" => dataout(1) <= NOT hamin(1);
                    dataout(0) <= hamin(0);
                    dataout(2 TO 3) <= hamin(2 TO 3);
                WHEN "110" => dataout(2) <= NOT hamin(2);
                    dataout(3) <= hamin(3);
                    dataout(0 TO 1) <= hamin(0 TO 1);
                WHEN "111" => dataout(3) <= NOT hamin(3);
                    dataout(0 TO 2) <= hamin(0 TO 2);
                END CASE;

            --double error
            ELSIF (syndrome(0) = '0') AND (syndrome(3 DOWNTO 1) /= "000") THEN
                ne <= '0';
                ded <= '1';
                sec <= '0';
                dataout(0 TO 3) <= "0000";
            END IF;
        END PROCESS;
    END arch;

Порождающая матрица для систематического кода Хэмминга (7,4)

    | 1  0  0  0    0  1  1 |
    | 0  1  0  0    1  0  1 |
    | 0  0  1  0    1  1  0 |
    | 0  0  0  1    1  1  1 |

Собственно возможен и несистематический код Хэмминга (7,4)
вот для него пораждающая матрица
    | 1  1  0  1  0  0  0 |
    | 0  1  1  0  1  0  0 |
    | 0  0  1  1  0  1  0 |
    | 0  0  0  1  1  0  1 |

Проверочная матрица для систематического кода Хэмминга (7,4)

    | 1  1  0  1  1  0  0 |
    H =	| 0  1  1  1  0  1  0 |
    | 1  0  1  1  0  0  1 |

        |1|
        |0|
    H * |0|     |1|
        |0|  =  |0|
        |0|     |1|  синдром
        |0|
        |0|

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

    Если синдром = 0, то ошибки нет

Соответсвенно:
    ---------------------------
    Синдром		Коррекция
    ---------------------------
    000		0000000
    001		0000001
    010		0000010
    011		0010000
    100		0000100
    101		1000000
    110		0100000
    111		0001000
    ---------------------------

  Код Хэмминга 11/7

    ------------------------
    p1 p2 p3 p4     error bit
    ------------------------
    E  E  +  +	d1
    E  +  E  +	d2
    +  E  E  +	d3
    E  E  E  +	d4
    E  +  +  E	d5
    +  E  +  E	d6
    E  E  +  E	d7
    E  +  +  +	p1
    +  E  +  +	p2
    +  +  E  +	p3
    +  +  +  E	p4
    +  +  +  +	no errors
    ------------------------

остальные синдромы - это уже множественные ошибки.

11/7 - Естественно может только исправлять одиночные ошибки.

Например если двойная ошибка в d1 и d2 то имеем:

    ------------------------
    p1 p2 p3 p4
    ---------------------
    +  E  E  +	- как будто ошибка в d3.
    ------------------------

Если добавить еще один бит общей четности то будет 12/7 - он сможет еще
и находить двойные ошибки.

  Код Хэмминга 15/5

Hamming(15,5)

Порождающая матрица

      |	1 0 0 0 0 1 0 1 0 0 1 1 0 1 1 |
      |	0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 |
      |	0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 |
      |	0 0 0 1 0 1 0 0 1 1 0 1 1 1 0 |
      |	0 0 0 0 1 0 1 0 0 1 1 0 1 1 1 |

  Длинна кодов Хэмминга

                    Полная длинна  	Длинна данных
Для исправления одиночных ошибок: 	2**M - 1	 2**M - 1 - M
Для исправления одиночных и
обнаружения двойных:		  	2**M		 2**M - 1 - M
                    (M - число проверочных символов)

Код Хэмминга - это абсолютный минимум, код меньшей длинны с такими
свойствами построить нельзя.

        - distance 3 -	- distance 4 -
    Info	Control	Total 	Control	Total
    bits	bis	bits    bits	bits
    1	2	3	3	4
    <=4	3	<=7	4	<=8
    <=11	4	<=15	5	<=16
    <=26	5	<=31	6	<=32
    <=57	6	<=63	7	<=64
    <=120	7	<=127	8	<=128


16.4. ГЕОМЕТРИЧЕСКИЙ СМЫСЛ ДИСТАНЦИИ

Пример пространство состояний - N-мерный куб.
Каждая вершина отличается от соседней в одном бите (код Грея).

Дистанция - расстояние между кодовыми словами (в битах).

Пространства состояний (размерности от 1 до 4):

Пример пространства состояний (трехмерный куб).

Пример пространства состояний (четырехмерный куб).

Предположим что мы имеем два правильных состояния: 000 и 111.
Ошибка исправляется в сторону ближайшего значимого значения.
(код корректирует единичную ошибку). дистанция = 3.

У кода исправляющего одинарную ошибку и замечающего двойную
дистанция будет равна 4:
(Берем опять гиперкуб размерности 4 с кодами 0000 и 1111)

                  дистанция 4
                +--------------------------------------+
        |                                      |
           одинарная	двойная      одинарная
    код  ----- ошибка ----- ошибка ----- ошибка  ---- код
    0000       0001         0011          1011        1111
    <------------			      ------------->
         исправляется			       исправляется

@HR
У кода исправляющего двойные ошибки дистанция будет 5.
(Берем опять гиперкуб размерности 5 с кодами 00000 и 11111)

            дистанция 5
          +---------------------------------------------------+
      |                                                   |
           одинарная	  двойная      двойная     одинарная
   код  ----- ошибка ----- ошибка ----- ошибка  ---- ошибка ---- код
   00000      00001	   00011	01011	     11011	 11111
    <--------------------------          -------------------------->
      исправляется				исправляется

И вообще чтобы увеличить количество исправляемых ошибок на 1 надо
увеличить дистанцию на 2.

d	D	C
1	0	0	Код невозможен
2	1	0	Parity bit
3	1	1	detect 1, correct 1
3	2	0	detect 2, correct 0
4	3	0	detect 3, correct 0
4	2	1	detect 2, correct 1
5	4	0	detect 4, correct 0
5	3	1	detect 3, correct 1
5	2	2	detect 2, correct 2
.........

Для обнаружения N ошибок:
    dmin = N + 1

Для исправления N ошибок:
    dmin = 2*N + 1

Для исправления N ошибок и обнаружения M ошибок:
    dmin = 2*N + M + 1

d  N  M
1  0  0	 отличие одной комбинации от другой
2  0  1  выявление одиночной ошибки
3  1  0  исправление одиночной ошибки
3  0  2  выявление двойной ошибки
4  1  1
4  0  3  выявление тройной ошибки
5  2  0	 исправление двойной ошибки
5  1  2  исправление одиночной ошибки + выявление двойной ошибки
5  0  4  выявление четверной ошибки

Но знание бита где произошла ошибка - расширяет наши возможности
по коррекции.


16.4.1. ГРАНИЦА ХЭММИНГА

         t
    ---
    \      n
    /    (   )  <= 2^(n-k)
    ---    i
    i=0

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

Для недвоичных кодов граница Хэмминга равна:

         t
    ---
    \      n
    /    (   ) (q - 1)^i  <= q^(n-k)
    ---    i
    i=0

Совершенные коды

Двоичный код Хэмминга		(2^m - 1, 2^m - m - 1, 3)
Недвоичный код Хэмминга		((q^m-1)/(q-1), (q^m-1)/(q-1) - m - 1, 3)
Код повторение	                (n, 1, n)
Проверка на четность		(n, n-1, 2)
Двоичный код Голея		(23, 12, 7)
Троичный код Голея		(11, 6,  5)

код (X,Y,Z)

    X - количество символов в коде
    Y - количество символов несущих информацию
    Z - дистанция


16.4.2. КОД ГОЛЕЯ

Код Голея (23, 12, 7)
Marcel J.E. Golay

Способен исправлять тройные ошибки.

Порождающая матрица для кода Голея:

| 1 0 0 0 0 0 0 0 0 0 0   1 0 0 1 1 1 0 0 0 1 1 1 |
| 0 1 0 0 0 0 0 0 0 0 0   1 0 1 0 1 1 0 1 1 0 0 1 |
| 0 0 1 0 0 0 0 0 0 0 0   1 0 1 1 0 1 1 0 1 0 1 0 |
| 0 0 0 1 0 0 0 0 0 0 0   1 0 1 1 1 0 1 1 0 1 0 0 |
| 0 0 0 0 1 0 0 0 0 0 0   1 1 0 0 1 1 1 0 1 1 0 0 |
| 0 0 0 0 0 1 0 0 0 0 0   1 1 0 1 0 1 1 1 0 0 0 1 |
| 0 0 0 0 0 0 1 0 0 0 0   1 1 0 1 1 0 0 1 1 0 1 0 |
| 0 0 0 0 0 0 0 1 0 0 0   1 1 1 0 0 1 0 1 0 1 1 0 |
| 0 0 0 0 0 0 0 0 1 0 0   1 1 1 0 1 0 1 0 0 0 1 1 |
| 0 0 0 0 0 0 0 0 0 1 0   1 1 1 0 0 0 0 0 1 1 0 1 |
| 0 0 0 0 0 0 0 0 0 0 1   0 1 1 1 1 1 1 1 1 1 1 1 |

Троичный код Голея

| 1 1 1 2 2 0 1 0 0 0 0 |
| 1 1 2 1 0 2 0 1 0 0 0 |
| 1 2 1 0 1 2 0 0 1 0 0 |
| 1 2 0 1 2 1 0 0 0 1 0 |
| 1 0 2 2 1 1 0 0 0 0 1 |


16.4.3. КОДЫ РИДА-МИЛЛАРА

THIS SECTION IS UNDER CONSTRUCTION

Основаны на мажоритарной логике
Reed-Muller

Порождающая матрица RM(3,1)

    | 1 |  | 1  1  1  1   1  1  1  1 |
    | X1|  | 0  0  0  0   1  1  1  1 |
    | X2|  | 0  0  1  1   0  0  1  1 |
    | X3|  | 0  1  0  1   0  1  0  1 |

Порождающая матрица RM(3,2)

    | 1 1 1 1 1 1 1 1 |
    | 1 0 1 0 1 0 1 0 |
    | 1 1 0 0 1 1 0 0 |
    | 1 1 1 1 0 0 0 0 |
    | 1 0 0 0 1 0 0 0 |
    | 1 0 1 0 0 0 0 0 |
    | 1 1 0 0 0 0 0 0 |


16.5. CRC (ЦИКЛИЧЕСКАЯ КОНТРОЛЬНАЯ СУММА)

CRC (Cyclical Redundancy Check) - циклический код для обнаружения ошибок.
CRC не исправляет ошибки, но позволяет их обнаруживать.

В общем то CRC это остаток от деления двоичного многочлена блока данных
на образующий полином.
Но деления не двоичного, а на поле Галуа GF(2^N).
Т.е. вместо вычитания используется XOR.

Эварист  Галуа (1811-1832).

Есть определенные трудности с тем какое число больше, какое меньше
на поле Галуа.
Потому что и сложение и вычитание - это XOR.
Пример:	1001 = 1010 + 0011    (в смысле на GF)
    1001 = 1010 - 0011
Кстати:  A + 0 = A
     A - 0 = A
Поэтому для сравнения чисел действует правило:
    X > Y, если позиция старшей 1 в X более значима чем в Y.
А дальше все как в обычном делении.

Пример вычисления CRC:
    Блок данных:		101110101010
    Образующий полином:	10011		x^4 + x + 1
                 ----
                 размер CRC = 4 бита (т.к. полином четвертой
                              степени).

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

Деление:
    1011101010100000
    10011
    -----
    00100
      10001
      10011
      --------
      00010
         10010
         10011
         -------
         00001
         11000
         10011
         -------
         01011
          10110
          10011
          ------
          001010
            1010  => CRC = 1010

На посылку идет: 101110101010 1010
         ------------ ----
            Data      CRC

Теперь посмотрим какой результат будет для пересланного блока:

    1011101010101010
    10011
    -----
    00100
      10001
      10011
      --------
      00010
         10010
         10011
         -------
         00001
         11010
         10011
         -------
         01001
          10011
          10011
          -------
          00000
            0000   => поделилось нацело

Не любой образующий полином подходит.
Он должен обладать следующими свойствами:

Допустим:
    T - передаваемое сообщение  (последние W бит - это CRC).
    G - образующий полином

    T mod G = 0

при ошибке получаем вместо T  - T(+)E, где Е - вектор ошибки
    (T(+)E) mod G = E mod G

Обнаружение одинарных ошибок:
    E = 1000..0000
        01.....000
        ...
        000....001
    чтобы их обнаружить наш полином должен иметь по крайней мере
    два единичных бита.

Обнаружение двойных ошибок:
    полином не должен иметь множителей вида:
        11
        101
        1001
        10001
        итд
        100...001

Обнаружение нечетного числа ошибок:
    полином должен иметь четное число единичных бит

Обнаружение пакетных ошибок
    E = 000111..11000
    E можно преобразовать в 1000.0001...1
    полином должен иметь младший бит = 1
    пока G шире чем 1..1 в E, ошибка обнаруживается

    Вероятность пакетной ошибки с длинной больше W
    примерно равна (0.5)^W

Стандартные образующие полиномы:

CRC-12:		X^12 + X^11 + X^3 + X^2 + X + 1
CRC-16: 	X^16 + X^15 + X^2 + 1
CRC-CCITT:      X^16 + X^12 + X^5 + 1
CRC-32:		X^32 + X^26 + X^23 + X^22 + X^16 + X^12 +
          + X^11 + X^10 + X^8  + X^7  + X^5  + X^4  + X^2 + X + 1
        (обратите внимание нечетное число бит).

CRC-24:		X^24 + X^23 + X^14 + X^12 + X^8 + 1
CRC-8:		X^8 + X^7 + X^6 + X^4 + X^2 + 1
CRC-4:		X^4 + X^3 + X^2 + X + 1

Вычисление CRC может легко быть проведенно аппаратно.
Для этого используются LFER (Linear Feedback Shift Register) - сдвиговые
регистры с линейной обратной связью.

THIS SECTION IS UNDER CONSTRUCTION

Пример LFER для CRC-16:

Пример LFER для CRC-32:

Кроме CRC LFER используются для генерации последовательности ПСЧ (псевдо-
случайных чисел).


16.6. КОДЫ РИДА-СОЛОМОНА

THIS SECTION IS UNDER CONSTRUCTION

Коды Рида-Соломона (Reed-Solomon code, RS-code)

Пусть I - информация, которую надо передать
      G - порождающий полином, степень полинома равна числу
      дополнительных символов
          Для исправления ошибок надо 2 дополнительных символа на одну ошибку.
      (т.е. для исправления 4 ошибок надо 4*2 = 8 доп символов)
      плюс один символ.
      (не стоит забывать что длинна G так же должна включать все комбинации
       места, где произошла ошибка).

тогда C - данные которые надо передать (wire)
      C = I * G

    +-------------------------+
on wire |           C             |
    +-------------------------+
    |		    |     |
    +- - - - - - - - - -+- - -+
          I бит       G бит

Пусть при передаче произошла ошибка:
    в результате мы получили вместо C:
         V = C + E,  где E - вектор ошибки
    Вычисляем синдром:
         S = V mod G
    если S = 0, то ошибки нет
    если S != 0, то каждый S можно однозначно соотнести с E
    (конечно при условии, что E входит в класс ошибок которые мы
     защищаем и опять таки нужен правильный выбор многочлена).

Пример:
    пусть полином G = X^3 + X^2 + 1   (G = 1101)
              степень 3 (исправляет одну ошибку, на длинне
                данных = 4).

    I данные = 1011
    C = 1011 * 111
        1011
          *	1101
       ---------
        1011
               0000
              1011
             1011
      -----------
      C= 1111111

Ecли все верно то:
    1111111 mod 1101
    1101
    -------
      1011
      1101
    -------
       1101
       1101
    -------
          0

    V mod G = (C mod G) + (E mod G)
                 = 0
    V mod G = E mod G = S

надо брать такой G, что бы S был уникальный для всех синдромов:

Считаем синдром для ошибки:
1	2	3	4	5	6	7
1000000	0100000	0010000	0001000	0000100	0000010	0000001
1101     1101     1101     1101 ------- ------- -------
------- ------- ------- -------     100     010     001
 1010     1010     1010     101
 1101     1101     1101
------- ------- -------
  1110     1110     111
  1101     1101
------- -------
    110     011

(если код исправляет также двойные и выше ошибки - синдромов будет больше
 и они будут иметь вид (для двойной ошибки)):
    1000001 1000010 1000100 ... ...
    0100001 0100010 0100100 ...
    ....
    0000101 0000110
    0000011

Теперь попробуем для нашего сообщения  1111111.
Пусть в нем возникла ошибка в бите 2 cверху:  1011111

Делим на прождающий многочлен:
    1011111
    1101
    -------
     1101
     1101
    -------
        011 => смотрим таблицу синдромов - ошибка 0100000, те в бите 2.

Корректируем, затем вычисляем результат.

Другой метод - Систематическое кодирование.
Он более удобен так как пересылаются реальные данные.

сообщение состоит из информационных битов, за ними следует ECC (т.е. как в CRC).

    +-------------------------+
on wire |         I         | ECC |
    +-------------------------+
    |		    |     |
    +- - - - - - - - - -+- - -+
          I бит       G бит

    наш полином G = X^3 + X^2 + 1   (G = 1101)
    те же данные = 1011

дополняем 3 нулевыми битами (т.к. порождающий полином степени 3)
CRC =   1011000 mod 1101
    1101
    -------
     1100
     1101
    -------
        100	= это CRC (Реально уже ECC).

Пересылаем:
    1011 100
    ---- ---
      данные CRC

Проверка:
    1011100 mod 1101
    1101
    -------
     1101
     1101
    -------
        нет ошибки

Пусть ошибка в бите 2 справа (как и в прошлый раз):
        1111100 mod 1101
    1101
    -------
      1010
      1101
    -------
       1110
       1101
    --------
        011 => смотрим таблицу синдромов - ошибка 0100000, те в бите 2.

Все опять таки происходит на полях Галуа:
Поля Галуа существуют только для числа элементов равного
    Простое_Число^Целая_Степень

Для поля GF(2) имеем:
    сиволы: 0 и 1
    правила:
        0 + 0 = 0	0 + 1 = 1	1 + 1 = 0
        0 - 0 = 0	1 - 1 = 0	1 - 0 = 1	0 - 1 = 1
        0 * 1 = 0	1 * 1 = 1
        0 / 1 = 0	1 / 1 = 1

Пример порождающих полиномов

степень	полином			n	k
1	11			3	2	Контроль четности
2	111			3	1	Код с повторением
3	1101			7	4	Хэмминг
    1011			7	4	Xэмминг
4	11001			15	11	Хэмминг
    10011			15	11	Хэмминг
    10111			7	3	Файр-Абрамсон
    11101			7	3	Файр-Абрамсон
5	100101			31	26	Хэмминг
    101001			31	26	Хэмминг
    ....
    где n - длинна кодового слова
        k - длинна блока исходного сообщения

мы наблюдаем сразу пары - это двойственность.
Если   ab...yz - порождающий многочлен, то zy...ba - тоже.

Код Хэмминга - частный случай кода Рида-Соломона (но самый продвинутый).

Коды Боуза-Чоудхури-Хоквенгема (Bose-Chadhuri-Hocquenghem - BCH) - обобщение
кодов Хэмминга, которое позволяет исправлять множественные ошибки.

n  	k     	t	g(x)
7	4	1	13
15	11	1	23
    7	2	721
    5	3	2467
31	26	1	45
    21	2	3551
    16	3	107657
    11	5	5423325
    6	7	313365047
63	57	1	103
    51	2	12471
    45	3	1701317
    39	4	166623567
    36	5
    30	6
    24	7
    18	10
    16	11
    10	13
    7	15
127	120	1	211
    113	2	41567
    106	3	11554743
    99	4
    92	5
    85	6
    78	7
    71	9
    64	10
    57	11
    50	13
    43	14
    36	15
    29	21
    22	23
    15	27
    8	31
255	247	1	435
    239	2	267543
    231	3
    223	4
    215	5
    207	6
    199	7
    191	8
    187	9
    179	10
    171	11
    163	12
    155	13
    147	14
    139	15
    131	18
    123	19
    115	21
    107	22
    99	23
    91	25
    87	26
    79	27
    71	29
    63	30
    55	31
    47	42
    45	43
    37	45
    29	47
    21	55
    13	59
    9	63

Мы можем использовать MATLab для выбора порождающих полиномов
pol = cycpoly(n,k)
    где n - длинна кодового слова
        k - длинна блока исходного сообщения

  CIRC

Для борьбы с большими пакетными ошибками используются CIRC
(Cross-Interleave Reed-Solomon code).

Данные сперва кодируются кодом Рида-Соломона по строкам/столбцам:

    +-----------+
    | --------->|
    | --------->|
    | --------->|
    | --------->|
    +-----------+

Затем результат кодируется снова кодом Рида-Соломона но уже по столбцам/строкам:

    +------------+
    | |  |  |  | |
    | |  |  |  | |
    | |  |  |  | |
    | |  |  |  | |
    | V  V  V  V |
    +------------+

Принцип Cross-Interleave:

В результате пакетная ошибка расслаивается на простые, которые легко
устраняются:

К примеру так устроена Error correction на компакт-дисках (CD).

Коды Рида-Соломона с точки зрения математики

Cauchy Reed-Solomon code


16.7. КОД БЕРГЕРА

Код Бергера - пример нелинейного кода.
У кода Бергера проверочные символы содержат число единиц в информационной
части кода.

    +---+---+---+---+---+
    | I | I | I | P | P |
    +---+---+---+---+---+

    000.00 		(число единиц = 0)
    001.01          (число единиц = 1)
    010.01
    011.10		(число единиц = 2)
    100.01
    101.10
    110.10
    111.11


16.8. СВЕРТОЧНЫЕ КОДЫ

THIS SECTION IS UNDER CONSTRUCTION

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

За счет завимости выхода от предидущего состояния уменьшается число
допустимых состояний - появляется избыточность.

Пример сверточного кодера:

Пример значаений на выходе в зависимости от состояния:

Недостаток сверточных кодов - трудно декодировать ошибки
(Метод максимального правдоподобия)

Пример сверточный код (6,3)
(6 - длинна блока, 3 - длинна информационных символов.

Кодер для сверточного кода (6,3):

Решетчатая диаграмма для сверточного кода (6,3):

Синдромный декодер для сверточного кода (6,3):


16.9. ТУРБО КОДЫ

THIS SECTION IS UNDER CONSTRUCTION

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

Турбо-коды бывают разные (в зависимости от кодов лежащих в основе).
Могут быть сверточные, могут быть композиционные.

Интерес к Турбо-кодам обусловлен тем, что они позволяют еще больше
приблизится к границе Шеннона (хотя и естественно за счет больших
аппаратно-временных затрат.

Идея турбо кодов:

Пример турбо-композиционного кода:

Пример сверточного турбо-кодера:

Зависимость эффективности турбо-кодов от количества раундов декодирования:


16.9.1. EVENODD КОДЫ

THIS SECTION IS UNDER CONSTRUCTION


16.9.2. WEAVER КОДЫ

THIS SECTION IS UNDER CONSTRUCTION


17. КОД ГРЕЯ

    Код Грея (Gray code) - код в котором при переходе к следующему числу
меняется только один бит.

Frank Gray. физик Bell Telephony Labs в 1930х

Необходимость кода Грея:
    пример шаговые электродвигатели - отслеживание позиции.
    (если будет менятся более чем 1 бит - получим краевые эффекты).
    или логические автоматы со сложными состояниями.

    Gray code(N) = N xor (N/2)

Пример для 3х бит:

    N	N/2	GRAY
    000	000	000
    001	000	001
    010	001	0011
    011	001	010
    100	010	110
    101	010	111
    110	011	101
    111	011	100

Пример диска на 4-бит (бинарный код):

Пример диска на 4-бит (код Грея):

Конвертор бинарного кода в код Грея:

Конвертор кода Грея в бинарный код:

Пример отображения Кода Грея как функции от бинарного числа:

Код Грея симметричен

Построение кода Грея - симметрия:

      =====
    0
    1
      =====

отражаем

      =====
    0
    1
       ---
    1
        0
      =====

добавляем следущий разряд:

      ======
    00
    01
    --
    11
    10
      ======

отражаем:

      ======
    00
    01
    11
    10
    --
    10
    11
    01
    00
      ======

добавляем следующий разряд:

     =======
       000
       001
       011
       010
       ---
       110
       111
       101
       100
     =======

Gray(n,k)
    n - основание СЧ
    k - число цифр в коде

Только с четным n - имеет циклическую структуру как в двоичном
случае.

К сожалению для нечентых N - отражением не построить

      =====
    0
    1
    2
      =====

      =====
    2
    1
    0
       ---
    0
    1
    2
       ---
    2
    1
    0
      =====

Но вообще возможен симметричный код с переходом у нуля:

G(3,2)
      ======
    00
    01
    02
    12
    11
    10
    20
    21
    22
      ====== WRAP

G(3,3)
      =======
    000
    001
    002
    012
    011
    010
    020
    021
    022
    122
    121
    120
    110
    111
    112
    102
    101
    100
    200
    201
    202
    212
    211
    210
    220
    221
    222
      =======  WRAP

или код сохраняющий изменения на 1 между соседними значениями, но
не симметричный:

      ======
       00
       10
       11
       21
       20
       22
       12
       02
       01
      ======

для четных n проблем нет:

      =====
    0
    1
    2
    3
      =====

      =====
    0
    1
    2
    3
       ---
    3
    2
    1
    0
       ---
    0
    1
    2
    3
       ---
    3
    2
    1
    0
      =====

G(4,2)
     ======
       00
       01
       02
       03
       --
       13
       12
       11
       10
       --
       20
       21
       22
       23
       --
       33
       32
       31
       30
     ======

G(4,3)

  (0 0 0) (0 0 1) (0 0 2) (0 0 3) (0 1 3) (0 1 2) (0 1 1) (0 1 0)
  (0 2 0) (0 2 1) (0 2 2) (0 2 3) (0 3 3) (0 3 2) (0 3 1) (0 3 0)
  (1 3 0) (1 3 1) (1 3 2) (1 3 3) (1 2 3) (1 2 2) (1 2 1) (1 2 0)
  (1 1 0) (1 1 1) (1 1 2) (1 1 3) (1 0 3) (1 0 2) (1 0 1) (1 0 0)
  (2 0 0) (2 0 1) (2 0 2) (2 0 3) (2 1 3) (2 1 2) (2 1 1) (2 1 0)
  (2 2 0) (2 2 1) (2 2 2) (2 2 3) (2 3 3) (2 3 2) (2 3 1) (2 3 0)
  (3 3 0) (3 3 1) (3 3 2) (3 3 3) (3 2 3) (3 2 2) (3 2 1) (3 2 0)
  (3 1 0) (3 1 1) (3 1 2) (3 1 3) (3 0 3) (3 0 2) (3 0 1) (3 0 0)

Есть вариант построения кодировки для десятичных (типа как BCD,
но обладающий свойствами кода Грея.

Decimal Gray code in one of variants:

 --------------------
 Decimal      Gray
 Digit        Code
 --------------------
  0          0000
  1          0001
  2          0011
  3          0010
  4          0110
  5          1110
  6          1010
  7          1011
  8          1001
  9          1000
 --------------------

В принципе код Грея - это непересекающая закольцованная линия проходящая
через все клетки карты Карно.


18. РЕГИСТРЫ

Def
===
    РЕГИСТР - совокупность 2х или более D-триггеров с общим
          тактовым сигналом и логикой управления.

Пример регистра:

Пример регистра с тристабильным выходом:
(OE = Output Enable)

Пример регистра с схемами загрузки

  Последовательно-паралельные регистры


19. ШИННЫЕ БУФЕРА И ШИННЫЕ ФОРМИРОВАТЕЛИ

THIS SECTION IS UNDER CONSTRUCTION

Двунаправленный интерфейс с шиной:

Двунаправленный интерфейс с шиной на VHDL:

    library ieee;
    use ieee.std_logic_1164.all;

    entity BIDIR is
        port(
            y    : inout std_logic;
                 e,a  : in    std_logic;
                 b    : out   std_logic
            );
    end BIDIR;

    architecture ARCH of BIDIR is
    begin
        process(e,a)
        begin
            case e is
                when '1' => y <= a;
                when '0' => y <= 'Z';
                when others => y <= 'X';
            end case;
        end process;
        b <= y;
    end ARCH;

Выходной элемент
(может работать как с открытым коллектором, так и с высоким импедансом).

(a) - буфер шины
(б) - приемопредетчик шины
(в) - регистр-фиксатор шины

Двунаправленный шинный формирователь.

Активный bus holder


20.1. ЦАП

  ЦАП

Def
===
    ЦАП (Цифрово-аналоговый преобразователь)
    [DAC (Digital-Analog converter)] - устройство, которое преобразует
    входной цифровой сигнал в аналоговую форму (напряжение).

        Типы DAC
        /       \
         R-2^NR     R/2R
      binary-weighted	stairstep
             input	лестничного
    с весовыми         типа
     регистрами

Изображение DAC (ANSI):

  ЦАП на весовых регистрах

Принципиальная схема DAC 4-бита на весовых регистрах:

Идея: цифровые сигналы ослябляются в пропорциональное весу разряда
      число раз, затем суммируются суммирующем ОУ.

Недостатки DAC на весовых регистрах:
      Очень трудно сделать пропорциональные резисторы
      (особенно внутри микросхемы).
      Результат: 1% ошибки у 7 бита = 2% ошибки у 6 = 256% ошибки у нулевого.

  ЦАП лестничного типа

Принципиальная схема DAC лестничного типа (на 4 бита):

Основная идея ЦАП: Базовое входное напряжение Vref делится на резисторах R
(на каждом вдвое). Затем каждый каскад ключем соединяется с выходом
(нарисованы обычные переключатели для простоты схемы, понятно что в
реальном оборудовании ключи электронные). Подключенные напряжения на выходе
суммируются и проходят через операционный усилитель.

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

  ЦАП интегрирующего типа

Еще существует ЦАП интегрирующего типа [Timed Integrator DAC]
Его основная идея - значение выводится на счетчик который на время
пропорциональное значению открывает вход который заряжает конденцатор
при операционном усилителе.

ЦАП интегрирующего типа

Временая диаграмма работы ЦАП интегрирующего типа:

  Ошибки и характеристики ЦАП

    Разрешающая способность
    Точность
    Погрешность смещения нуля
    Время установки сигнала
    Монотонность

Ошибки DAC:

Модель DAC на Verilog-AMS:

// N-bit Digital to Analog Converter
`include "disciplines.vams"
module dac (out, in, clk);
    parameter integer bits = 8 from [1:24]; // resolution (bits)
    parameter real fullscale = 1.0;         // output range is from 0 to fullscale (V)
    parameter real td = 0;                  // delay from clock edge to output (s)
    parameter real tt = 0;                  // transition time of output (s)
    parameter real vdd = 5.0;               // voltage level of logic 1 (V)
    parameter real thresh = vdd/2;          // logic threshold level (V)
    parameter integer dir = 1 from [-1:1] exclude 0; // 1 for rising edges, -1 for falling
    output out;
    input clk;
    input [0:bits-1] in;
    voltage out, clk;
    voltage [0:bits-1] in;
    real aout;
    integer weight;
    genvar i;
    analog begin
        @(cross(V(clk) - thresh, dir) or initial_step) begin
            aout = 0;
            weight = 2;
            for (i = bits - 1; i >= 0; i = i - 1 ) begin
                if (V(in[i]) > thresh) begin
                    aout = aout + fullscale/weight;
                end
                weight = weight*2;
            end
        end
        V(out) <+ transition(aout, td, tt);
    end
endmodule


20.2. АЦП

  AЦП

Def
===
    AЦП (Аналогово-цифровой преобразователь)
    ADC (Analog-Digital converter) - устройство, которое преобразует
    входной аналоговый сигнал (напряжение) в цифровую форму.

Изображение ADC (ANSI):

        АЦП
     ________|________
    /        |        \
Интегрирующие Поразрядно  Паралельные
            уравновешенные

  Интегрирующие АЦП

Интегрирующий {Ступенчатый} (Digital Ramp) (StairStep-Ramp)  АЦП
        внутри цифровой счетчик, регистр, ЦАП, и компаратор на ОУ.
    В начале цикла счетчик сбрасывается в 0.
    И начинает считать, напряжение все увеличивается и когда
    оно достигнет входного и компаратор это скажет, то
    регистр запишет текущее состояние и цикл повторится
    медленно, но дешево.

Идея ступенчатого АЦП:

Принципиальная схема ступенчатого АЦП (на 4 бита):

У интегрирующего АЦП результат преобразование чуть больше чем сигнал.

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

Двойной интегрирующий АЦП

Для повышения точности используют двойной интегрирующий АЦП:

Следящий АЦП:
    начинает как ступенчатый потом отслеживает изменения
    (результат что-то среднее между паралельным и ступенчатым).

Идея следящего АЦП:

  Поразрядно-уравновешенный АЦП

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

Плюсы:
    Время преобразование постоянно и не зависит от величины сигнала.
    Не слишком большая схема (по сравнению с паралельным АЦП).

Схема поразрядно-уравновешенного АЦП.

Алгоритм работы поразрядно-уравновешенного АЦП:

Времмая диаграмма работы поразрядно-уравновешенного АЦП:

У поразрядно-уравновешенного АЦП результат преобразование чуть
меньше чем сигнал.

  Паралельный АЦП

Паралельный АЦП (Flash)
    состоит из большого количества компараторов на ОУ
    самые быстрые, но и самые дорогие

Принципиальная схема паралельного ADC (на 2 бита):

Основная идея АЦП. Базовое напряжение Vref делится на N равных частей
резисторами R, и поступает на входы операционных усилителей.
На каждом усилителе если Vref(i) меньше чем Vin то на выходе будет 0,
иначе 1. Результат в конкретный момент записывается в регистр REG,
затем приоритетный шифратор CD кодирует его в двоичный код, который
в тот же момент записывается в выходной регистр REG2 из которого выбираются
данные.

Временная диаграмма:

На самом деле будут биения, лучше использовать код Грея:

Реальные ADC как правило имеют более 1024 Vref(i) каскадов.

  Конвеерный АЦП

Недостаток паралального АЦП - слишком много элементов.
Это обходится следующим образом.
Паралельный АЦП делится на каскады.

Каскад состоит из парелельного АЦП с малюм числом бит, ЦАП и схемы
аналогового вычитания.

В результате на следущий каскад идет уже ток для более младших бит.

  Ошибки АЦП

Ошибки ADC:

  Быстродействие и стоимость

Быстродействие и стоимость АЦП:

  Сложность построения

Модель ADC на Verilog-AMS:

// N-bit Analog to Digital Converter
`include "disciplines.vams"
module adc (out, in, clk);
    parameter integer bits = 8 from [1:24];// resolution (bits)
    parameter real fullscale = 1.0; // input range is from 0 to fullscale (V)
    parameter real td = 0;          // delay from clock edge to output (s)
    parameter real tt = 0;          // transition time of output (s)
    parameter real vdd = 5.0;       // voltage level of logic 1 (V)
    parameter real thresh = vdd/2;  // logic threshold level (V)
    parameter integer dir = 1 from [-1:1] exclude 0; // 1 for rising edges, -1 for falling
    input in, clk;
    output [0:bits-1] out;
    voltage in, clk;
    voltage [0:bits-1] out;
    real sample, midpoint;
    integer result[0:bits-1];
    genvar i;
    analog begin
        @(cross(V(clk)-thresh, +1) or initial_step) begin
            sample = V(in);
            midpoint = fullscale/2.0;
            for (i = bits - 1; i >= 0; i = i - 1 ) begin
                if (sample > midpoint) begin
                    result[i] = vdd;
                    sample = sample - midpoint;
                end else begin
                    result[i] = 0.0;
                end
                sample = 2.0*sample;
            end
        end
        for (i = 0; i < bits; i = i + 1) begin
            V(out[i]) <+ transition(result[i], td, tt);
        end
    end
endmodule


20.3. ГЕНЕРАТОРЫ СИГНАЛОВ

На базе DAC можно строить генераторы аналоговых сигналов.
(Их можно строить и на аналоговых компонентах тоже).

  Пилообразной формы

RESET ------+
            |
    +-------+    +-----+
CLK ----|Counter|====| DAC |---- Vout
    |       |    |     |
    +-------+    +-----+
            |
                Vref

  Произвольной формы:

RESET ------+
            |
    +-------+   +-----+   +-----+   +-----+
    |Counter|===| RAM |===| REG |===| DAC |---- Vout
    |	|   | ROM |   |     |   |     |
    +-------+   +-----+   +-----+   +-----+
        |                    |        |
CLK  -------+--------------------+        Vref


21. ДВОЙНАЯ СИНХРОНИЗАЦИЯ

Идея: различные стадии синхронизировать по разному,
      тогда на уровне RTL (Register Transfer Layer) не будет гонок.
      т.е. вход на следующий этап конвеера записывается в другой
      момент времени чем на текущий этап.

Пример синхронного сдвигового регистра.

Пример синхронного сдвигового регистра с двойной синхронизацией.

Пример динамического синхронного сдвигового регистра с двойной синхронизацией

Пример динамического расширителя импульса.
Если импульс маленький то его можно продлить:

А вообще можно делать столько стадий сколько надо


22. ДЕТЕРМИНИРОВАННЫЕ КОНЕЧНЫЕ АВТОМАТЫ

THIS SECTION IS UNDER CONSTRUCTION

Детерминированный конечный автомат [ДКА] (DFA).
В принципе все процессы внутри чипов реализуются в виде
детерминированных конечных автоматов.
Мы рассмотрим их основные разновидности

  Автомат Мура

Автомат Мура
    (Выходы зависят только от состояния)

    +-------+	+--------+	+--------+
IN ---->| Next  |	|Current |	| Output |
    | Stage |------>|Stage   |--+-->| Logic  |--------> OUT
    | Logic |	|Register|  |	| (Combo)|
    +-->|(Combo)|	+--------+  |   |	 |
    |	+-------+		    |	+--------+
    |                               |
    +-------------------------------+

  Автомат Милли

Автомат Милли
    (Выходы зависят от состояний и входов)

IN ---------+-------------------------------+
            |                               |
        V                               V
    +-------+	+--------+	+--------+
    | Next  |	|Current |	| Output |
    | Stage |------>|Stage   |--+-->| Logic  |--------> OUT
    | Logic |	|Register|  |	| (Combo)|
   +--->|(Combo)|	+--------+  |   |	 |
   |	+-------+	            |	+--------+
   |                                |
   +--------------------------------+


24. CPLD И FPGA

THIS SECTION IS UNDER CONSTRUCTION

Flexware

PLD	Programming logic devices

SPLD	Simple PLD (both PLA and PAL)

  PLA

PLA	Programming logic array
    small FPD contain 2 level of logic AND and OR plane,
    both planes is programmable

  PAL

PAL	Programmable array logic
    small FPD contain programmable AND plane, fixed OR plane

Logic expander:

    PAL GAL
    CUPL

Lattice PAL16L8:

Как мы видим контакты:
    10		GND
    1-9,11		in
    13-18		in/out
    12,19		out
    20		VCC

Пример программы на PALASM для дешифратора:
-----------------------------------------------------------------------

TITLE	 Address Decoder
PATTERN	 Test 1
REVISION A
AUTOR	 AVP
COMPANY	 PHG
DATA	 26/2/06
CHIP	 DECODER1 PAL16L8
; pins 1   2   3   4   5    6  7   8    9   10
       A10 A11 A12 A13 A14 A15 A16 A17	A18 GND
; pins 11  12 13  14  15  16  17   18  19  20
       A19 NC A20 A21 A22 A23 A24  NC  CS  VCC

EQUATIONS

/CS = A24 * A23 * A22 * A21 * A20 * A19 * A18 * A17 * A16
    + A24 * A23 * A22 * A21 * /A11 * /A10

-----------------------------------------------------------------------

  CPLD

CPLD	Complex PLD
    multiple SPLD blocks in single chip

  FPGA

FPGA	Field Programmable Grid Array
    Structure allow very high logic capacity

    Lookup table
    CLB (configurable logic block)

FPGA

характеристики современных FPGA

Когда делают новый техпроцесс первым делом на нем выпускают не процессоры
а FPGA.

Military Xilinx Vertex-4E стоит $20,000 за chip.

    ------------------------------
    тип	Экивалентных вентилей
    ------------------------------
    SPLD	0-200
    CPLD	200-12000
    FPGA	1000-1000000
    ------------------------------

Xilinx	Virtex		Full-feature SRAM-based FPGA
    Spartan		Low-cost reduced version
    CoolRunner	CPLD
Altera	Stratix		SRAM based FPGA
    Cyclone		Low-cost reduced version
    MAX		CPLD
    MAX-II		Flash based CPLD
Actel			Antifuse based FPGA (radiation tolerant)
            Flash based FPGA
Lattice			CPLD (EEPROM)
            Flash based FPGA

    Высокая плотность
    Энергонезависимость
    Не репрограммируются


25. ПАМЯТЬ

THIS SECTION IS UNDER CONSTRUCTION


25.0 SRAM (СТАТИЧЕСКАЯ ПАМЯТЬ)

SRAM (Static Random Access Memory)

обозначение памяти SRAM 16x1 (16 бит).
DIN/ANSI

Вот так выглядит ячейка SRAM построенная по CMOS технологии.

Топология:

Запись в ячейку:
    Устанавливают X, X' = X#
    затем активируют линию word line.

Чтение ячейки:
    активируют линию word line.
    если ячейка хранит 1 то  X = 1, X' = 0
    если ячейка хранит 0 то  X = 0, X' = 1

    +-----+    +------------+
A0	| DC  |    |  Memory    |
  ====>	|Line |--->|  Matrix    |
Ai	|     |    |            |
    +-----+    +------------+
             ^  ^  ^
                 |  |  |
             V	V  V
Ai+1	+-----+	   +------------+
   ====>| Ctl |--->|   MUX      |
An	|     |    +------------+
EN ---->|     |      ^      |
WE ---->|     |      |      |
    +-----+      |      V
                 DI     DO

EN - Enable
WE - Write Enable
DI - Data in
DO - Data out

Поведенческая модель Generic SRAM на VHDL:

    library ieee;
    use ieee.std_logic_1164.all;

    entity gsram is
        generic(
            data_width : integer := 8;
                addr_width : integer := 8);
        port(
            DI : in std_logic_vector((data_width-1) downto 0);
                EN : in std_ulogic;		-- Enable
                WE : in std_ulogic;		-- Write enable
                RST: in std_ulogic; 		-- Reset
                CLK: in std_ulogic; 		-- Clock
                  ADDR : in std_logic_vector((addr_width-1) downto 0);
                    DO:  out std_logic_vector((data_width-1) downto 0));
    end gsram;

    architecture Beh of gsram is
            constant depth      : integer := 2 ** addr_width;
        constant TR	    : time    := 5 ns;
        type mem_type is array(depth-1 downto 0) of
                 std_logic_vector(data_width-1 downto 0);

        function a_value(BV:in std_logic_vector) return natural is
            variable E: natural := 0;
        begin
            for i in BV'LOW to BV'HIGH loop
                E := E * 2;
                if BV(i) = '1' then
                    E := E + 1;
                elsif BV(i) /= '0' then
                    report "Wrong bit";
                    E := 0;
                    exit;
                end if;
            end loop;
            return	E;
        end a_value;

    begin
        process(clk)
            variable mem:mem_type;
        begin
            if rising_edge(clk) then
                if (EN = '1') then
                    if (RST = '1') then
                        do <= (others => '0');
                    elsif (WE = '1') then
                        mem(a_value(addr)) := di;
                    elsif (WE = '0') then
                        do <= mem(a_value(addr)) after TR;
                    end if;
                end if;
            end if;
        end process;
    end beh;

  Времеменные диаграммы

Чтение:

Запись:

  Оптимизация

Оригинальная 6T ячейка:

Оптимизация:

Результат (4T ячейка):

Для сравнения ячейка SRAM на TTL технологии.

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

  Многопортовая память

Иногда требуется чтобы к памяти были паралельные обращения
в одно и тоже время (естественно не на запись в одну и ту же ячейку)
[Например процессор и видеоадаптер в видеопамять].
Можно сделать так что бы к ячейке могли иметь доступ сразу
несколько клиентов:
Пример такой структуры на транзисторах.
(Очень похожа на ячейку SRAM, но в целях уменьшения числа транзисторов
используются не 2 инвертора для хранения, а 2 транзистора).

  CMOS RAM

Почему на материнской плате батарейка?
Что бы работали часы. А в часах еще находится CMOS RAM.
Где и хранятся настройки BIOS. Ее мало (не больше 256 байт).
Она CMOS значит мало жрет т.к. не переключается.
Все транзисторы закрыты в tristate - идет только ток утечки.

Как же все это запитанно?

Когда есть питание все работает от сети, когда нет то от батареи.


25.1. ROM

ПЗУ (постоянное запоминающее устройство)
ROM (read-only memory)

Пример ROM 4x4  (16 бит)

ПЗУ состоит из дешифратора и матрицы памяти.
В матрице памяти в каждом кружочке может быть а может не быть ячейка ПЗУ.

Диодное ПЗУ - ячейка ПЗУ сделана на диодах
Когда линия Ci выбрана дешифратором диод пропускает ток на выходную
линию Yi.

Транзисторное ПЗУ - ячейка сделана на транзисторе.
Когда линия Yi выбрана дешифратором транзистор открыт и доводит уровень
линии Ci до 0 (Ci подпитывается от питания).

Поведенческая модель ROM на VHDL:
(ROM c конкретным содержанием на 16 байт):

    library ieee;
    use ieee.std_logic_1164.all;

    entity VROM16 is
        port(
                 X : in std_logic_vector(0 to 3);
                 Y : out std_logic_vector(0 to 7));
    end VROM16;

    architecture Example of VROM16 is
        signal	S:std_logic_vector(0 to 7);
    begin
        process(X,S)
        begin
            case X is                                   -- Data
                when "0000" => S <= "11111111";     -- FF
                when "0001" => S <= "11101110";     -- EE
                when "0010" => S <= "11011101";     -- DD
                when "0011" => S <= "11001100";     -- CC
                when "0100" => S <= "10111011";     -- BB
                when "0101" => S <= "10101010";     -- AA
                when others =>   S <= "00000000";   -- 00
            end case;
            Y <= S;
        end process;
    end Example;


25.2. PROM

PROM - это однократно программироваемое ПЗУ с плавкими перемычками.
Ячейка PROM очень похожа на ячейку транзисторного ROM

Это часть схемы PROM. С0-С4 - это выходы дешифратора матрицы.
Программирование осуществляется так: подается адрес, один из Ci становится
активным, затем подается 12.5V на DO (Data output). Стабилитрон пробивается
в результате через плавкую перемычку открытую транзистором по Ci течет ток
больше чем 10 mA (к примеру) и она сгорает.


25.3. EPROM И EEPROM

EPROM - это программироваемое ПЗУ (стираемое ультрафиолетовыми лучами).
В EPROM используются транзисторы с плавающим затвором.
(Как правило микросхема имеет сверху окошко, заклеенное наклейкой,
через которое ее можно стирать.
Кстати были варианты и без окошка, которые стирались ренгеновскими лучами,
но населению это не сильно нравилось ;)

Транзистор с плавающим затвором:

В состоянии 0:

В состоянии 1:

Ячейка EPROM идейно очень похожа на ячейку транзисторного ROM

  EEPROM

EEPROM - Electrical Erased Programming ROM

В отличии от EPROM EEPROM стирается не ультрафиолетовыми лучами
а электрическим током (порядка 12V, сейчас есть и более низковольтные варианты).

В чем отличие EEPROM от Flash:

  EEPROM - 2T структура
  Flash  - 1T структура

Собственно говоря этот лишний транзистор предохраняет ячейку от стирания.
В EEPROM мы можем стереть отдельную ячейку памяти.
Во Flash мы стираем целый блок. В результате Flash более плотно упакован,
но стирание не random access, а блочное.

1T структура:

2T структура:


25.3.1. FLASH

FLASH - это программироваемое ПЗУ с электрическим стиранием.
Во Flash также как и в EPROM используются транзисторы с плавающим
затвором.

Ячейка FLASH выглядет как ячейка EPROM, только у нее другие электрические
характеристики, которые позволяют разрядить плавающий затвор электрически
не прибегая к УФ.

Транзистор с плавающим затвором в разных режимах:

Strata Flash - технология разработанная Intel позволяющая хранить более
одного бита в ячейке.
Идея: использовать не наличие/отсутствие заряда в плавающем затворе (1 бит),
      а оценивать его количество (2 бита).

Пример реализации:

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

    --------------------------------
    OP3	OP2	OP1  |	Result
    ---------------------+----------                      	заряд затвора
    0	0	0    |	00		нет сигнала  	   0
    0	0	1    |  01		слабый сигнал      0.33FULL
    0	1	1    |  10		средний сигнал	   0.66FULL
    1	1	1    |	11		cильный сигнал	   FULL
    --------------------------------

Уровни выходных сигналов плавающего транзистора во Flash:

Mirror Bit Flash

AMD сделала Mirror Bit Flash.
В одном транзисторе хранятся два бита за счет того что линии стока и истока
меняется местами. Заряд накапливается в углах.

  NOR Flash

NOR Flash - основная идея: все транзисторы закрыты.
Если транзистор выбран, то в зависимости от состояния плавающего
затвора он либо не открывается, либо открывается пропуская землю
на линию бита.
(Линия бита тянется ко всем ячейкам, и линия земли тоже).

  NAND Flash

NAND Flash - основная идея: ячейки в цепочку друг за другом
Если транзистор не выбран то пропускают сигнал, если выбран то зависит
от плавающего затвора. Он либо пропускает сигнал либо нет.
(Плюсы: не надо тащить линии земли и бита по кристаллу - занимает
меньше места,
Минусы: работает медленнее).

Сравнение размера NOR и NAND Flash:

3D структуры

Компания Matrix разработала 3х мерные Flash структуры

Организация Flash


25.3.2. FeRAM

FeRAM (Ferroelectric RAM) - новая технология в области энергонезависимой
памяти. Ячейки FeRAM выглядят как ячейки DRAM, но в FeRAM используются
FE конденсаторы (которые имеют гистерезис), благодаря этому они сохраняют
свое состояние при выключенном питании.

Ячейка DRAM и FeRAM:

FeRAM гистерезис:

Состояния 0 и 1:

1T ячейка FeRAM

Строение FE транзистора:

Строение FE конденсатора:

Конденсаторная матрица:

Дублирование FeRAM структур для повышения надежности:


25.4. DRAM

DRAM - это динамическая память. В основе ее лежит ячейка с микро-конденсатором:
Запись:	Транзистор открывается, сигнал с линии бита зарежает конденсатор.
Чтение: На линию бита выставляется сигнал посредине между 1 и 0.
    Транзистор открывается, чуствительный элемент на линии бита
    определяет куда изменилось напряжение.
    После чего происходит запись тех же данных в ту же ячейку
    Считанные данные выдаются наружу
Регенерация:
    На линию бита выставляется сигнал посредине между 1 и 0.
    Транзистор открывается, чуствительный элемент на линии бита
    определяет куда изменилось напряжение.
    После чего происходит запись тех же данных в ту же ячейку
    Считанные данные не выдаются никуда.

Общая структура DRAM:

как это выглядет физически:

А это топология:

  Регенерация

DRAM Matrix делят на 2 части.
В случае чтения или Refreshа READ_REFRESH становится активным.
И котнроллер регенерации ведет себя как триггер в неустойчивом
состоянии. Открытая ячейка DRAM (конденсатор) на шине A или B
выводит триггер в сторону 1 или 0 (на другой шине Tristate - все закрыто).
Триггер входит в устойчивое состояние соответствующие данным и
с помощью обратной связи выдает значение на шину - заряжая конденсатор
которой только что использовался для установки этого триггера.

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

  Чередование банков памяти

После обращения к DRAM ячейкам нужно время для регенерации.
Однако если мы поделим память на банки, то сможем в это время обращаться
к другим банкам
(Это особенно удобно учитывая что современные процессоры стараются выбирать
память в cache строками).

  Как происходит работа DRAM

Запись:

Чтение:

Регенерация:


25.4.1. СИГНАЛЫ DRAM

Классический DRAM:

       DRAM                            DRAM
      256Kx1                           1Mx1
    +--------+			+--------+
    A8  |   o    | GND              DI  |   o    | GND
    DI  |	 | CAS#            W/R# |        | DO
   W/R# |	 | DO              RAS# |        | CAS#
   RAS#	|        | A6               A10 |        | A9
    A0  |        | A3                A0 |        | A8
    A2  |        | A4                A1 |        | A7
    A1  |        | A5                A2 |        | A6
   Vcc  |        | A7                A3 |        | A5
        +--------+                  Vcc |        | A4
                    +--------+

Сигналы:
    A0-Ai	(адресс (строка или столбец))
    DI	(Data in)  вход данных
    DO	(Data out) выход данных
    W/R#	(Write/Read#) чтение или запись
    RAS#	(Raw Address select#) выбор строки
    CAS#	(Column Address select#) выбор столбца
    Vcc	питание
    GND	(Ground) земля

Временная диаграмма работы DRAM:
Чтение:

Ранняя запись:

Поздняя запись:

RAS-Регенерация:

THIS SECTION IS UNDER CONSTRUCTION


25.4.2. ЭВОЛЮЦИЯ DRAM

 ---------------------------------------------
         Slow	Fast 	CAS tf	Cycle
Year	Size	 ns     ns      ns      ns
 ---------------------------------------------
1980 	64K bit  180 	150 	75 	250
1983 	256K bit 150 	120 	50 	220
1986 	1M bit   120 	100     25 	190
1989 	4M bit   100 	80 	20 	165
1992 	16M bit  80 	60 	15 	120
1996 	64M bit  70 	50 	12 	110
1998 	128M bit 70 	50 	10 	100
2000 	256M bit 65 	45 	7 	90
2002 	512M bit 60 	40 	5 	80
2004 	1G bit   55 	35 	5 	70
2006 	2G bit   50 	30 	2.5 	60
 ---------------------------------------------

    o DRAM
    o FPM DRAM	(Fast Page Mode)
    o EDO DRAM	(Extended Data out)
    o BEDO DRAM	(Burst EDO)
    o SDRAM		(Synchronous DRAM)
    o DDR SDRAM	(Double Data Rate SDRAM)
    o DDR2 SDRAM	(Quad Data Rate SDRAM)

    o RDRAM		(Rambus DRAM)

Поскольку современные микропроцессоры стараются читать/писать в память
сразу строки cache, то обычно используются burst cycles для доступа к
памяти (т.е. последовательное чтение или запись из подряд идущих адресов.
Время записывается в виде:

    Число_тактов_для_получения_первого_байта_в_пакете -
    Число_дополнительных_тактов_для_получения_второго_байта_в_пакете -
    Число_дополнительных_тактов_для_получения_третьего_байта_в_пакете -
    итд.

Тип DRAM	Sync/Async	Timing		   	Total Burst
DRAM		Async		5-5-5-5                 20
FPM		Async		5-3-3-3                 14
EDO		Async		5-2-2-2                 11
BEDO		Async		5-1-1-1                 8
SDRAM		Sync		5-1-1-1                 8
DDR		Sync		5-1/2-1/2-1/2		~6.5
DDR2		Sync		5-1/4-1/4-1/4           ~5.75
RDRAM		RamBus		vary

Состовляющие цикла в асинхронной памяти:
    Установка RAS -   2
    Установка CAS -   2
    Выборка данных -  1

    ----------------
    Cycle   Clock
    Time    Speed
    (ns)    (MHz)
    ----------------
    60.0 	16.67
    15.0 	66.67
    10.0 	100.00
    7.5  	133.33
    6.0  	166.67
    5.0  	200.00
    3.8  	266.67
    3.0  	333.33
    2.5  	400.00
    1.9  	533.33
    ----------------

  DRAM

DRAM - самая старая и медленная.
Для доступа к каждому адрессу надо ставить RAS и CAS.
Цикл 5-5-5-5

Как повысить быстродействие?
Разбивают память на банки которым отдельно ставят RAS# и CAS#.

  FPM

FPM (Fast Page Mode).
Для  доступа один раз ставится RAS, затем ставятся CAS
Цикл 5-3-3-3
FPM-60ns 22MHz

Начиная с FPM поддерживается CAS before RAS регенерация:
(внутри микросхемы находится регистр который инкреминтируется
при каждом refresh цикле).

и Hidden-Refresh:
(RAS# дают еще раз при включенном CAS#).

  EDO

EDO (Extended Data Out).
Для доступа один раз ставится RAS, затем ставятся CAS
В микросхеме стоят защелки на выходе, и DATA выводится во время
когда уже запускают следующий CAS.
Цикл 5-2-2-2
EDO-60ns 33MHz

  BEDO

BEDO (Burst EDO)
Один раз ставится RAS и CAS, а умная память выдает данные для
последовательных банков подряд.
Цикл 5-1-1-1

  SDRAM

SDRAM (Synchronous DRAM)
Имеет сигнал тактирования CLK
Похожа на BEDO, но поскольку сигналы синхронизируются по CLK
это позволяет поднять тактовую частоту.
SDRAM работает на частоте 66MHz и выше.

У SDRAM сигналы RAS#, CAS#, WE# используются также как команды:

    RAS# 	CAS# 	WE#
    1	1	1	NOP
    0	1	1	Activate bank
    1	0	0	Write
    1	0	1	Read
    1	1	0	Burst Terminate
    0	1	0	Precharge
    0	0	1	Autorefresh
    0	0	0	Load Mode Register

SDRAM READ:

SDRAM WRITE:

SDRAM REFRESH:

SDRAM PRECHARGE:

SDRAM LOAD_MODE:

Архитектура SDRAM (include DDR and DDR2):

Как мы видем формируется набор COL для всех банков и данные одновременно
выбираются в защелки откуда их уже и выбирают.

Структура микросхемы SDRAM:

SDRAM	64bit modules
 ------------------------------
PC66    533 MB/sec	10ns
PC100	800 MB/sec	8ns
PC133	1064 MB/sec	7.5ns
 ------------------------------

  DDR

DDR (Double Data Rate)
Данные выставляются не только по спаду CLK, но и по фронту.
Для более тщательного управления на высоких частотах используется
дополнительная линия BQ, которой управляет тот кто выставляет данные
на шину, эта линия изменяется каждый раз когда выставляются данные.
DDR использует DLL (Delay Locked Loops) для синхронизации данных.

DDR READ:

DDR WRITE:

DDR SDRAM 64 bit modules

 ----------------------------------------
Name	clk
 ----------------------------------------
PC1600  100Mhz	1600MB/sec	DDR200
PC2100	133Mhz	2133MB/sec	DDR266
PC2400	150Mhz	2400MB/sec	DDR300
PC2700	167Mhz	2666MB/sec	DDR333
PC3000	183MHz	2933MB/sec	DDR366
PC3200	200MHz	3200MB/sec	DDR400
PC3600  222MHz	3555MB/sec	DDR444
PC4000  250MHz	4000MB/sec	DDR500
PC4300	267MHz	4266MB/sec	DDR533
PC4400				DDR550
 ----------------------------------------

PCxxxx = (DDRyyy * 64bit) / 8
             bus speed

  DDR-II

DDR2 (Double Data Rate 2)
Данные выдаются еще быстрее чем CLK/2.
Линия BQ используется.
Для задержек используются специальные схемы фазовой подстройки
внутри памяти (DLL (Delay Locked Loops)) для синхронизации данных.

 -------------------------------------------------------
        clock   M   	DRAM    	MB/sec
name	MHz  trasnfers  name            /DIMM 	DIMM
 -------------------------------------------------------
DDR 	133  	266 	DDR266 		2128 	PC2100
DDR 	150 	300 	DDR300 		2400 	PC2400
DDR 	200 	400 	DDR400 		3200 	PC3200
DDR2 	266 	533 	DDR2-533 	4264 	PC4300
DDR2 	333 	667 	DDR2-667 	5336 	PC5300
DDR2 	400 	800 	DDR2-800 	6400 	PC6400
DDR3 	533 	1066 	DDR3-1066 	8528 	PC8500
DDR3 	666 	1333 	DDR3-1333 	10,664 	PC10700
DDR3 	800 	1600 	DDR3-1600 	12,800 	PC12800
 -------------------------------------------------------

  RAMBUS

RAMBUS DRAM - это совершенно другая технология.
Технология последовательной шины памяти на которой сидят модули
которые в нужный момент выплевывают биты данных.

CTM (Clock to Master)
CFM (Clock from Master)
DQ  (Data)
CMD (Command)

Шина RAMBUS работает с частотой до 400MHz.

Пакет чтения:

DRDRAM Modules 64bit
 -------------------------------
PC600	2x300MHz   1200 MB/sec
PC700	2x356MHz   1424 MB/sec
PC800	2x400MHz   1600 MB/sec
 -------------------------------

Технология была не очень отработанная и в настоящее время в PC
DRDRAM убита DDR и DDR-II, которые при той же или большей производительности
существенно дешевле.

  Специальные дополнения

Registered DRAM
    Для повышения надежности использует регистры для адрессных и коммандных
сигналов и PLL clock buffer для коррекции времен.

ECC
    Содержит дополнительные биты данных которые используются для ECC коррекции
    Например если обычный модуль памяти имеет шину данных 64-бит
    то ЕСС имеет шину данных 72-бит.

    SEC 	- Single Error Correcting
    SECDED  - Single Error correcting, Double Error detected
          Дистанция 4

    -----------------------------------
    Bits	SEC		SECDED
    -----------------------------------
    1	1 (100%)	3 (300%)
    32	1 (3%)		7 (22%)
    64	1 (1.6%)	8 (13%)
    N	1 (1/N)		1 + log2(N)
    -----------------------------------


25.5. ОБЩИЕ ПРИНЦИПЫ РАСШИРЕНИЯ СИСТЕМ ПАМЯТИ

THIS SECTION IS UNDER CONSTRUCTION

  Увеличение разрядности памяти

  Увеличение адрессного пространства памяти


30. МИКРОПРОЦЕССОР (CPU)

Основные узлы:

    o  ALU   (Arithmetical-Logical Unit)
    o  Register File
    o  CU    (Control Unit)
    o  BUI   (Bus Interface Unit)
    o  Cache
    o  FPU   (Floating-Point Unit)
    o  MMU   (Multi-media Unit)

Пример: AMD K6

ALU совершает арифмитечески-логические операции. это главный центр
вычислений процессора.

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

CU - управляющий модуль - выбирает из памяти и декодирует команду,
управляет всеми другими узлами (выдает управляющие сигналы)

BIU - модуль взаимодействия с шиной - управляет внешней шиной,
позволяет общаться процессору с внешним миром.

Еще внутри процессора находятся несколько шин по которым передаются данные
между узлами процессора.

На рисунке пути передачи данных в процессоре:

  Выборка комманды

Команда выбирается в CU (стрелка Prefetch) через Result Bus из внешней
шины (External Bus) через BIU (стрелка Load).

  Вычисления

Вычисления выполняются в ALU. Операнды берутся из Register File
один напрямую (стрелка без надписи), другой через Source Bus (стрелки OP1).
Результат записывается обратно в Register File через Result Bus
(стрелки Result).

  Загрузка из памяти

Регистры загружаются из памяти (External Bus) через BIU (стрелка Load)
затем Result Bus в Register File.

  Выгрузка в память

Регистры записываются в память из Register File через Source Bus (стрелка OP1)
в BIU (стрелка Store) и из него на External Bus.

  Условный переход

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

  Все вместе

В последующих секциях мы рассмотрим каждый из блоков процессора более детально.
Мы будем называть Source Bus - Bus A, стрелочку от Register File к ALU - Bus B,
а Result Bus - Bus C


30.1. ALU

ALU - (Arithmetical-Logical Unit) - это место где происходят все вычисления
в процессоре.

ALU как черный ящик имеет следующий интерфейс:

Входы:
    Bus A    - операнд 1
    Bus B    - операнд 2
    FlagsIn  - некоторые флаги нужные для операций (CF)
    Control  - управляющие линии для выбора операций. (команда)
Выходы:
    Bus C    - результат
    Flags    - флаги получившиеся в результате выполнения команды

          +--------+
              |        |
     A   ------- >|        |
                  |        |-------- > C (Result)
     B   ------- >|        |
          |        |
     FlagsIn --- >|        |-------- > Flags
          +--------+
              ^
              |
            Control

  Блок-схема ALU

ALU состоит из следующих блоков:

    o Сумматор/Вычитатель
      используются для сложения/вычитания чисел и для изменения
      знака числа (-x).
      так же позволяет делать сложение/вычитание с CF (carry flag),
      что позволяет программно обрабатывать числа большей разрядности.
      Так же используется для сравнения чисел.
    o Логический блок
      Вычисляет инверсию и двухоперандные логические функции.
    o Shifter (сдвиговый регистр)
      Осуществляет сдвиги и циклические сдвиги.
      (так же через CF)
    o Multiplier (умножитель)
      Умножает числа.
    o Некоторые ALU реализуют еще и частичное деление
          (деление занимает много тактов и каждый такт вычисляется
       только один шаг деления).

Какой из блоков используется в текущий момент и как определяют линии Control.

  Типичные операции в ALU

 ------------------------------------------------------------------
Логические	NOT		C = not A
        AND		C = A and  B
        OR		C = A or   B
        XOR		C = A xor  B
        NAND		C = A nand B
        NOR		C = A nor  B
 ------------------------------------------------------------------
Арифметические	NEG		C = -A			C = A# + 1
        ADD		C = A + B
        ADC		C = A + B + CF
        SUB		C = A - B		C = A + B# + 1
        SBC		C = A - B - CF		C = A + B# + CF#
 ------------------------------------------------------------------
Сравнение	CMP		Set_Flags(A - B) 	результат игнорируется
        TEST		Set_Flags(A and B)	результат игнорируестся
 ------------------------------------------------------------------
Сдвиговые	SHL		C = A << N
        SHR		C = A >> N
        SAL		C = A << N
        SAR		C = A >>> N
        ROL		rotate left
        ROR		rotate right
        RCL		rotate left with CF
        RCR		rotate right with CF
 ------------------------------------------------------------------
Умножение	MUL 		C = A * B   	    беззнаковое
        IMUL		C = A * B	    знаковое
Деление		DIV 		C = A / B	    знаковое
        REM		C = A % B	    остаток от деления
        IDIV		C = A / B	    беззнаковое
        IREM		C = A % B              остаток от деления
 ------------------------------------------------------------------

Логические операции описаны в разделе 4.2.
Арифметические операции описаны в разделе 11.*.

Сравнение:

    -------------------------------------------
        Числа		Условие		ZF CF OF
    -------------------------------------------
    Без знака	A > B		0  0  -
    Без знака	A == B		1  0  -
    Без знака	A < B		0  1  -
    -------------------------------------------

Сдвиги:

            +--+      +-------------+
    SHL/SAL		|CF| < -- |             | <-- 0
            +--+      +-------------+

                      +-------------+      +--+
    SHR		   0 --- >|             |  --> |CF|
                              +-------------+      +--+

                  +-------------+      +--+
    SAR	            +--- >|             |  --> |CF|
                        |     +-------------+      +--+
                +------+
            при арифметическом сдвиге старший бит
            копируется сам в себя.

            +--+       +------------+
    ROL		|CF| < -+- |            |< --+
            +--+	|  +------------+    |
                +--------------------+

                  +-------------+       +--+
    ROR		     +-- >|             |--+--> |CF|
                         |    +-------------+  |    +--+
                 +---------------------+

            +--+     +--------------+
    RCL	    +---|CF|< ---|              |< --+
                |   +--+     +--------------+    |
            +--------------------------------+

            +---------------+     +--+
    RCR	   +-- >|               |--- >|CF|--+
           |    +---------------+     +--+  |
           +--------------------------------+

Пример простого однобитового ALU:


30.1.1. РЕАЛИЗАЦИЯ ALU НА VHDL.

Это пример реализации простого 4-х битного ALU на VHDL:
(Сигналы можно посмотреть в тексте программы ниже).

Управляющие сигналы:

    EN - Enable - 	разрешает использовать ALU
                  без этого сигнала ALU не работает
    ENX - Enable Output - разрешает вывод результата на шину C
                 (например для комманды CMP это не надо)
    OPCODE - Operation code - команда для ALU:
            000000	NOT B
            000001	A AND  B
            000010	A OR   B
            000011  A XOR  B
            000101	A NAND B
            000110  A NOR  B
            000111  A EQV  B
            001000	A SHL  1
            001001  A SHR  1
            010010  A RCL  1
            010011  A RCR  1
            010100  A SAL  1
            010101  A SAR  1
            100000  -A
            100001  A + B
            100010  A + B + CF
            100100  A - B
            100101  A - B - CF

    Как реализовать команды не требующие результата?
        ENX  OPCODE
        1    100100	  A - B	    (SUB)
        0    100100   Flg(A - B)    (CMP) no result, only flags set
        1    000001       A and B   (AND)
        0    000001   Flg(A and B)  (TEST) no result, only flags set

--
-- ALU_N.vhd
--
-- Generic ALU implementation
--

library ieee;
use ieee.std_logic_1164.all;

entity alu_N is
    generic(N: positive);
    port(
        A: in std_logic_vector((N-1) downto 0);	   -- Input Bus 0
        B: in std_logic_vector((N-1) downto 0);    -- Input Bus 1
        C: out std_logic_vector((N-1) downto 0);   -- Output Buse
        CI: in std_logic;			   -- carry flag in

        EN: in std_logic;			   -- Enable
        ENX: in std_logic;			   -- Enable Output
        RST: in std_logic;			   -- Reset

        OPCODE: in std_logic_vector (5 downto 0);  -- Opcode

                               -- Flags output
        CFLG: out std_logic;                         -- Carry flag
        ZFLG: out std_logic;			   -- Zero flag
        SFLG: out std_logic;			   -- Sign flag
        OFLG: out std_logic			   -- Overflow
    );
end  alu_N;

architecture Example of alu_N is

component add_NC is
    generic(N: positive);
    port(
        A: in std_logic_vector((N-1) downto 0);
        B: in std_logic_vector((N-1) downto 0);
        X: out std_logic_vector((N-1) downto 0);
        C: out std_logic;
        CI: in std_logic
    );
end component;

signal	AA: std_logic_vector((N-1) downto 0);
signal  BB: std_logic_vector((N-1) downto 0);
signal  CC: std_logic_vector((N-1) downto 0);
signal  CCX: std_logic_vector((N-1) downto 0);
signal  CFXX: std_logic := '0';

signal	CFX: std_logic := '0';
signal  ZFX: std_logic := '0';
signal  SFX: std_logic := '0';
signal  OFX: std_logic := '0';
signal	CIX: std_logic := '0';

signal	use_adder : std_logic := '0';

begin
    --  Main opcode parsing -------------------------
    process(EN,OPCODE,A,B,CI)
    begin
        use_adder <= '0';
        case OPCODE is
        when "000000" =>		-- NOT B
            CC <= not B;
        when "000001" =>		-- AND
            CC <= A and B;
        when "000010" =>		-- OR
            CC <= A or B;
        when "000011" =>		-- XOR
            CC <= A xor B;
        when "000101" =>		-- NAND
            CC <= A nand B;
        when "000110" =>		-- NOR
            CC <= A nor B;
        when "000111" =>		-- EQV
            CC <= not (A xor B);
        when "001000" =>		--  SHL
            CC  <= '0' & A(N-1 downto 1);
            CFX <= A(0);
        when "001001" =>		-- SHR
            CC <= A(N-2 downto 0) & '0';
            CFX <= A(N-1);
        when "010010" =>		-- RCL
            CC <= CI & A(N-1 downto 1);
            CFX <= A(0);
        when "010011" =>		-- RCR
            CC <= A(N-2 downto 0) & CI;
            CFX <= A(N-1);
        when "010100" =>		-- SAL
            CC <= '0' & A(N-1 downto 1);
            CFX <= A(0);
        when "010101" =>		-- SAR
            CC <= A(N-2 downto 0) & A(N-1);
            CFX <= A(0);
        when "100000" =>		-- NEG
            AA <= not A;
            BB <= (BB'range => '0');
            CIX <= '1';
            use_adder <= '1';
        when "100001" =>		-- ADD
            AA <= A;
            BB <= B;
            CIX <= '0';
            use_adder <= '1';
        when "100010" =>		-- ADC
            AA <= A;
            BB <= B;
            CIX <= CI;
            use_adder <= '1';
        when "100100" =>		-- SUB
            AA <= A;
            BB <= not B;
            CIX <= '1';
            use_adder <= '1';
        when "100101" =>		-- SBC
            AA <= A;
            BB <= not B;
            CIX <= not CI;
            use_adder <= '1';
        when others =>			-- Default Zero
            CC <= (CC'range => '0');
        end case;
    end process;

    -- Adder mapping ----------------------------------
     XADD:  add_NC
     generic map (N => N)
     port map(
            A => AA,
            B => BB,
            X => CCX,
            C => CFXX,
        CI => CIX);

    --  Output data process --------------------------
    process(CCX,CC,CFXX,OPCODE)
    begin
        case ENX is
            when '1' =>
                if (use_adder = '1') then
                    C <= CCX;
                    CFLG <= CFXX;
                else
                    C <= CC;
                    OFX <= '0';
                    SFX <= CC(N-1);
                end if;
                CFLG <= CFX;
                ZFLG <= ZFX;
                OFLG <= OFX;
                SFLG <= SFX;
            when others =>
                C <= (C'range => 'Z');
        end case;
    end process;
end Example;

Результат синтеза ALU на 4бита.


30.2. ФАЙЛ РЕГИСТРОВ

Файл регистров (Register file) - это многопортовая сверхоперативная
память, которая используется для хранения обрабатываеммых данных.

Файл регистров как черный ящик:

        +---------+
        |+-------+|
        ||  R0   ||< ------- A
        |+-------+|
     C  ------ >||  ...  ||
        |+-------+|< ------- B
        ||  RN   ||
        |+-------+|
        +---------+
            ^
            |
          Control

Cигналы:

Вход:
    Шина С  - для записи в файл регистров
    Control - управляющие входы:
        EN_A  - разрешить bus A
        EN_B  - разрешить bus B
        EN_C  - разрешить bus C
        REG_A - выбор регистра для шины A
        REG_B - выбор регистра для шины B
        REG_C - выбор регистра для шины C
        CLK   - синхросигнал
            [в отличии от ALU необходим т.к. внутри триггеры]
            (как правило выборка на A,B по фронту,
             запись из C по спаду)
            (но может быть и двойная синхронизация)
        RESET - cброс по включению питания
            (в принципе необязательно)
Выходы:
    Шина  A - чтение из файла регистров
    Шина  B - чтение из файла регистров

Общая архитектура регистрового файла:

Регистровый файл состоит из многопортовой памяти, защелок на шинах
и управляющего блока (который содержит дешифраторы для выборы конктретного
регистра на конкретную шину).
Эта архитектура допускает чтобы все 3 шины (A,B,C) были открыты на один
и тот же регистр.

Пример схемы для обработки бита в регистровом файле
(для одной шины).

Пример оптимизировааного на транзисторах бита файла регистров
для трех шин:

Это пример реализации Register File на VHDL:
(Синтезируется в использования Internal RAM в FPGA)

    library ieee;
    use ieee.std_logic_1164.all;

    entity regfile is
        generic(
            lnum_reg : integer := 4; -- logarithm of number of registers
            reg_width   : integer := 16);	-- register width
        port(
            REG_A: in std_logic_vector(lnum_reg-1 downto 0);
                 REG_B: in std_logic_vector(lnum_reg-1 downto 0);
                 REG_W: in std_logic_vector(lnum_reg-1 downto 0);
                 A:     out std_logic_vector(reg_width-1 downto 0);
                 B:     out std_logic_vector(reg_width-1 downto 0);
                 W:     in  std_logic_vector(reg_width-1 downto 0);
                 CLK:   in  std_logic;		-- clock
                 EN_A:  in  std_logic;		-- enable A
                 EN_B:  in	std_logic;		-- enable B
                 EN_W:  in  std_logic);		-- enable W
    end regfile;

    architecture RTL of regfile is
        constant num_reg : integer := 2 ** lnum_reg;  -- number of registers
        type rmem_type is array(num_reg-1 downto 0) of
                 std_logic_vector(reg_width-1 downto 0);

        function value(BV:in std_logic_vector) return natural is
            variable E: natural := 0;
        begin
            for i in BV'LOW to BV'HIGH loop
                E := E * 2;
                if BV(i) = '1' then
                    E := E + 1;
                elsif BV(i) /= '0' then
                    report "Wrong bit";
                    E := 0;
                    exit;
                end if;
            end loop;
            return	E;
        end value;

            signal TEMP_A: std_logic_vector(reg_width-1 downto 0);
        signal TEMP_B: std_logic_vector(reg_width-1 downto 0);
        signal WRL: std_logic := '0';
        shared variable	mem:rmem_type;
    begin
        process(CLK)
        begin
            if rising_edge(CLK) then
                TEMP_A <= (others => 'Z');
                TEMP_B <= (others => 'Z');
                if EN_A = '1' then
                    TEMP_A <= mem(value(REG_A));
                end if;
                if EN_B = '1' then
                    TEMP_B <= mem(value(REG_B));
                end if;
                if EN_W = '1' then
                    WRL <= '1' after 5 ns, '0' after 10 ns;
                end if;
            end if;
        end process;

        process(WRL)
        begin
            if WRL = '1' then
                mem(value(REG_W)) := W;
            end if;
        end process;

        A <= TEMP_A;
        B <= TEMP_B;
    end RTL;


30.2.1. ПРИМЕРЫ ФАЙЛА РЕГИСТРОВ

THIS SECTION IS UNDER CONSTRUCTION

В этой секции приведены примеры файла регистров для разных микропроцессоров:

  Zilog z80

  Intel 386

  Motorola MC68000

  MIPS R1000


30.3. CONTROL UNIT

Control Unit - сердце микропроцессора.  CU дает указания что делать всем
другим узлам микропроцессора.

Как он это делает?
В микропроцессоре существует специальный регистр называемый
PC (Program counter - программный счетчик) [иногда его называют
IP - Instruction pointer - указатель на инструкцию].
Это регистр указвает на место в памяти, где находится команда которую
процессор будет выполнять.

Процессор выбирает эту команду из памяти и помещает ее в Instruction Register.
И тут начинается самое интерестное:

         CU
           /   \
       Аппаратный  Микропрограммный

  Аппаратный CU

(регистр PC и схема выборки не показана)

Аппаратный CU дешифрует команду в набор сигналов (Instruction Decoder),
кроме того он содержит счетчик тактов (внутренних тактов - они имеют частоту
большую, чем частота процессора) Clock Counter. Этот счетчик соединен
с дешифратором и имеет схему сброса в 0 по запуску новой комманды.
Линии от Instruction Decoderа и от дешифратора входят в большой блок
комбинационной логики (не содержит триггеров) и на выходе получается
набор управляющих сигналов для блоков процессора).
[Кстати первое что делает эта логика - это выбирает команду из памяти и
ее дешифрует].
Плюсы:  высокое быстродействие
Минусы: жесткая конструкция - трудно исправлять ошибки и модернизивовать.

Последовательность работы аппаратного CU

1. Сбрасывается счетчик тактов в 0.
   Через дешифратор выбираются линия в комбинационной логике.
2. Логика выбирает следующую инструкцию из памяти
3. Инструкция помещается в Instruction Register и декодируется.

4. Входные линии от дешифратора счетчика тактов, регистра флагов и
   декодированной команды через логику формируют управляющие сигналы.
   Каждый такт счетчик увеличивается.
5. Один из управляющих сигналов сбрасывает счетчик тактов в 0 и
   все посторяется.

  Микропрограмный CU

Микропрограммный подход возник исторически:
Команды делают предопределенную последовательность действий.
Делать это аппаратно - сложно + большой размер схем (по тем временам)
[Тогда еще не было таких технологий и возможностей].
М.Уилкс в 1951 году предложил решить эту проблему software методом:
Микропрограммы (firmware).

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

CU содержит в себе новый регистры MPC (Microprogram Counter).
MPC является указателем инструкции внутри Microcode ROM.
Инструкции внутри microcode содержат адресс следующей микрокоманды
в microcode ROM, а так же управляющие сигналы для процессора.
(они могут порходить через комбинационную логику вместе с частью
декодированной команды) [но сложность этой логики на порядки ниже
чем в случае аппаратного CU].

Плюсы:  легкость модификации
Минусы:	быстродействие

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

Последовательность работы микропрограммного CU

1. MPC сбрасывается в 0.
2. Из Microcode ROM выбираеются микрокоманды начиная с адресса 0
   (в адрессе 0 сидит микропрограмма для выборки и декодирования инструкции)
3. Выбирается команда из памяти по адрессу PC. Обновляется PC.
4. Выбранная инструкция помещается в Instruction Register.

5. Инструкция декодируется
6. Результат декодирования - адресс в microcode ROM.
   Этот адресс заносится в MPC.

7. Данные из Microcode ROM, регистра флагов и части декодированной команды
   формируют управляющие сигналы микропроцессора и аддресс следующей
   микрокоманды.
8. При завершении команды адресс следующей микрокоманды ставится в 0.
   (и весь цикл повторяется).

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

Пример кусочка псевдо-микрокода:
    -----------------------------------------------------
        Register File     |           |      |
    ----------------------+     ALU   |  BIU |
    BUS A | BUS B | BUS R |           |      |
    -----------------------------------------------------
     0123 | 0123  | 0123  | CMD CF EO | EN   |
    -----------------------------------------------------
     -1--   --1-    ----  | ADD 0  0  | 0            Пример: ADD R3=R2+R1
     ----   ----    ---1  | ADD 0  1  | 0
    -----------------------------------------------------

Пример микрокоманд на примере учебного ARC CPU:

Нанокоманды:

Многоуровневые микрокоманды - основные содержаться в Control Unite -
они выдают стартовый адресс нанокоманды для соответствующего узла.
Узел выполняет нанокомманды (причем с большей тактовой частотой чем CU).

  Последовательность выполнения команды:

Посмотрим сейчас последовательность выполнения команды:
 ----------------------------------------------------------------------
0. Если установлен сигнал RESET, то загрузить			CU
   PC в предопределенное начальное значение (Init)
1. Проверить есть ли прерывания IRQ[0..J] которые можно 	CU
   обработать  [Прерывания могут быть маскированы флагом
   прерываний IF].
   Если да то запустить обработку прерывания (Interrupt)
   (т.e. сохранить состояние и загрузить в PC предопределенное
   значения).
2. Извлечения команды из памяти (Fetch)				BIU
3. Обновление PC (Fetch)					CU
3. Разшифровка команды (Decode)					CU
4. Вычисления адресса операнда [опционально]			ALU
5. Извлечение операнда						REG,BIU
6. Обработка данных  (Execute)					ALU
   (Может модифицировать PC)
7. Вычисления адресса результата [опционально]			ALU
8. Сохранение результата					REG,BIU
 ----------------------------------------------------------------------

  Prefetcher

Поскольку выборку команды преходится делать постоянно обычно ее выносят
в отдельный функциональный блок называемый prefetcher.

Prefetcher выбирает команды заранее, он работает паралельно с основной
частью CU. Prefetcher модифицирует PC (на самом деле PPC) после каждой
выбранной команды и в состоянии отслеживать безусловные переходы и
продолжать выбирать с нового адресса.
В современных процессорах prefetcher дружит с BTB (Branch Target Buffer),
который дает информацию о том произойдет ли условный переход или нет.
В случае если поток команд нарушается непредсказанным условным переходом
или возвратом prefetcher сбрасывается и начинает выбирать снова.


30.3.1. ВЫПОЛНЕНИЕ ТИПИЧНЫХ ОПЕРАЦИЙ

  ALU операции

  ALU операция регистровая

Используется:  Register File, ALU
Поля команды выбирают 2 регистра операнда, 1 регистр результата
и код ALU операции.
ALU выполняет операцию, результат записывается в Register File и
обновляется регистр флагов.

  ALU операция с непосредственным операндом:

Используется: Register File, ALU
Поля команды выбирают 1 регистр операнда, 1 регистр результата,
поля непосредственного числа выставляется на шину B прямо из команды
(дополняется 0 или 1 до нужной разрядности) и код ALU операции.
ALU выполняет операцию, результат записывается в Register File и
обновляется регистр флагов.

  Условные и безусловные переходы

  Абсолютный безусловный переход

Используется: CU
Адресс следующей комманды записывается в PC прямо из комманды.

  Относительный безусловный переход

Используется: CU
PC складывается с непосредственным числом из комманды (дополненным
0 или 1 до нужной разрядности) и результат записывается в PC.

  Непрямой переход

Используется: CU, Register File
Поля команды выбирают регистр в регистровом файле,
содержимое этого регистра записывается в PC.
Если у процессора есть prefetcher то он сбрасывается

  Условный относительный переход

Используется: CU, Flag Register
Из Flag Register выбирается флаг соответствующий полю в команде,
в зависимости от поля команды он инвертируется или нет.
Если полученный результат равен 1, то PC складывается с непосредственным
числом из комманды (дополненным 0 или 1 до нужной разрядности) и результат
записывается в PC.
Если результат равен 0, то ничего не делается.

  Загрузка/Выгрузка

  Загрузка регистра

Используется: AGU, BIU, Register File.
Поле Memory поступает в AGU (Address Generation Unit).
AGU выбирает регистры из Register File (при необходимости) и вычисляет
адресс, который передается в BIU. BIU читает память и выдает ее на шину C,
откуда она записывается в Register File.

  Выгрузка регистра

Используется: AGU, BIU, Register File.
Используется: AGU, BIU, Register File.
Поле Memory поступает в AGU (Address Generation Unit).
AGU выбирает регистры из Register File (при необходимости) и вычисляет
адресс, который передается в BIU. Из Register File выбирается регистр
(например на шину C). BIU пишет в память.

  Подпрограммы

  Вызов подпрограммы (абсолютный):

Используется: CU, AGU, BIU, Register File.
AGU выбирает SP (Stack Pointer) из Register File, вычисляет
адресс куда писать в stack и передает его BIU.
Паралельно ALU выбирает SP и обновляет его.
CU передает PC в BIU. BIU пишет PC в память (stack).
В PC записывают адресс из поля команды.

  Возврат из подпрограммы

(не показано, что надо очистить prefetcher)

Используется: CU, AGU, BIU, Register File.
AGU выбирает SP (Stack Pointer) из Register File, вычисляет
адресс откуда читать в stackе и передает его BIU.
Паралельно ALU выбирает SP и обновляет его.
BIU передает данные из памяти (из stack) в CU, CU записывает
их в PC.
Если у процессора есть prefetcher то он сбрасывается.

  Прерывания

Вызов прерывания:

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


30.3.1.1. РЕГИСТР ФЛАГОВ И УСЛОВИЯ

Микропроцессор содержит регистр флагов.
Флаги ставятся ALU по результатам операций и используются в операциях
условных переходов.

Как правило практически любой микропроцессор содержит флаги:

    Carry		Переноса
    Zero		Нуля
    Overflow	Переполнения
    Sign		Знака

Пример регистра флагов для Zilog Z80:

Пример регистра флагов для Intel 8086:

Для сравнения чисел обычно используют команду COMPARE (СРАВНЕНИЕ), которая
вычитает второй операнд из первого, но результат никуда не записывается,
а просто устанавливаются флаги.

    CMP	A,B     	;  Set_Flags(A-B)

Рассмотрим условия переходов и их связь с флагами и сравнениями на
примере нескольких процессоров:

  Условия в IA-32

Флаги:
    CF - carry
    OF - overflow
    ZF - zero
    SF - sign
    PF - parity

Условия:

 --------------------------------------------------------------------------
Abbr	 Unsigned Signed Condition		Description
 --------------------------------------------------------------------------
A/NBE	   >		 (CF==0) and (ZF==0)    Above/Not Below Equal
AE/NB/NC   > =		  CF==0	 		Above Equal/Not Below/Not Carry
B/NAE/C	   <		  CF==1			Below/Not Above Equal/Carry
BE/NA	   < =		 (CF==1) or  (ZF==1)	Below Equal/Not Above
E/Z	   ==     ==	  ZF==1			Equal/Zero
NE/NZ	   !=	  !=	  ZF==0			Not Equal/Not Zero
G/NLE		  >      (SF==OF) and (ZF==0) 	Greater/Not Less Equal
GE/NL		  >=     (SF==OF)		Greater Equal/Not Less
L/NGE		  <       SF!=OF		Less/Not Greater Equal
LE/NG		  <=	 (SF!=OF) or (ZF==1)	Less Equal/Not Greater
NO			  OF==0			Not Overflow
O			  OF==1			Overflow
NP/PO			  PF==0			No Parity/Parity Odd
P/PE			  PF==1			Parity/Parity even
NS			  SF==0			No Sign
S			  SF==1			Sign
 ---------------------------------------------------------------------------

  Условия в 68K

Регистр флагов для Motorola MC68000:

Флаги:
    C - carry
    V - overflow
    Z - zero
    N - sign

Условия:

 ---------------------------------------------------------------------------
Abbr	Unsigned Signed	Condition		Description
 ---------------------------------------------------------------------------
NE	!=	!=	Z==0			Not Equal
EQ	==	==	Z==1			Equal
HI	>		(C+Z)==0		Higher
LS	< = 		(C+Z)==1		Less Equal
HS	> =		C==0			Higher Equal
LO	<		C==1			Lower
GE		>=	(N xor V) == 0		Greater Equal
LT		<	(N xor V) == 1		Less That
GT		>	Z + (N xor V) == 0	Greater
LE		<=	Z + (N xor V) == 1	Less Equal
PL			N == 0			Plus
MI			N == 1			Minus
VC			V == 0			Overflow Clear
VS			V == 1			Overflow Set
T			always 1		True
F			always 0		False
 ---------------------------------------------------------------------------

TODO: Регистр флагов может содержать группы наборов арифметических флагов
      как у PowerPC.
TODO: Команды могут быть условные от флагов как в IA-64, HP-PA, ARM
TODO: Флаги есть у FPU тоже - их мы опишем в соответствующей секции


30.3.1.2. DECODER

THIS SECTION IS UNDER CONSTRUCTION

  RISC

  VLIW

  CISC


30.3.2. ADDRESS GENERATION UNIT

AGU (Address Generation Unit) служит для вычисления адрессов для
операндов находящихся в памяти.

Типичный Address Generation Unit:

При необходимости AGU выбирает из Register File регистры необходимые
для вычисления адресса операнда.
AGU имеет достаточно простую схему: несколько сумматоров и иногда
сдвиговый регистр. Результат вычислений AGU передает BIU.

  Режимы адресации

Режимы адрессации:
    o Прямая адресация
    o Косвенная адрессация
        Базовая
        Базовая со смещением  (индексная)
        Базово-индексная
        Базово-индексная со смещением
        (Косвенно-индексная)
        Регистровая

  Прямая адрессация

Адресс операнда содержится непосредственно в команде.
AGU только передает его BIU напрямую.

    variable
      |
      V
    DIRECT(variable_address)

  Косвенная адрессация (Абсолютная)

  Непрямая адрессация (Базовая)

В поле операнда содержится номер регистра. Регистр выбирается
из Register File и его содержимое является искомым адрессом.

     * variable_pointer
       |
       V
    BASE(register_contain_pointer)

  Базовая адрессация со смещением (индексная)

В поле операнда содержится номер регистра. Регистр выбирается
из Register File и его содержимое складывается со смещением (offset)
которое берется из поля операнда. Результат и есть адресс.

    struct -> field
        |
        V
    BASE(struct_addr) + OFFSET(field)

Базово-индексная адрессация:

В поле операнда содержится 2 регистра. Регистры выбираются,
и суммируются.

    array[index]
        |
        V
    BASE(array_addr) + INDEX(array_index)

Базово-индексная адрессация со смещением:

То же самое, что базово-индексная, но результат суммируется еще
и со смещением.

    struct.array[index]
        |
        V
    BASE(struct) + OFFSET(field) + INDEX(array_index)

Базовая-индексная адрессация с маштабирование индекса и смещением:

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

    struct.field[array_index]
        |
        V

BASE(struct) + OFFSET(field) + INDEX(array_index) * SCALE(array_element_size)

  Специальные виды адрессации

           Специальные виды адрессации
        /	     |          \
    Области быстрого   стековая   по указателю
    доступа            память       комманд

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

    stack
    |
    V
BASE(stack_pointer);
stack_pointer = stack_pointer + OPERAND_SIZE

    stack
    |
    V
stackpointer = stack_pointer + OPERAND_SIZE
BASE(stack_pointer)

    stack
    |
    V
BASE(stack_pointer)
stack_pointer = stack_pointer - OPERAND_SIZE

    stack
    |
    V
stack_pointer = stack_pointer - OPERAND_SIZE
BASE(stack_pointer)

Соответсвенно для выборки обратно инкремент/декремент и пост/пре меняются местами:

    ---------------------------
    Закладка	Выборка
    в stack		из stack
    ---------------------------
    [SP]++		--[SP]
    ++[SP]		[SP]--
    [SP]--		++[SP]
    --[SP]		[SP]++
    ---------------------------

Адрессация по указателю комманд:

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

Пример ссылок назад:
(желтая - наша команда, зеленое - место куда указывает IP, синее - место куда мы
хотим обратиться с помощью адрессации по указателю комманд).

и вперед:

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


30.3.2.1. СТЕК

Бывают архитектуры, где stack pointer аппаратно фиксирован,
например для x86 - есть масса комманд которые используют только SP.
Например:
    CALL
    PUSH
    INT

A есть архитектуры без явного выделения stack pointer, там регистр который
используется в качестве SP, определяется ABI.

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

В принципе стек может расти как вверх (к старшим адрессам) так и вниз
(к младшим адрессам)

Stack
    FILO (First In-Last Out)
    LIFO (Last  In-First Out)

    |         |
    |---------|	как магазин в автомате (из которого стреляют)
    |---------|
    |---------|
    +---------+

Операции со стеком:

        +---------+
    |         |	поместить в стек
    +---------+
             |
    |    V	  |
    |---------|
    |---------|
    |---------|
    +---------+

        +---------+
    |         |	выбрать из стека
    +---------+
             ^
    |    |	  |
    |---------|
    |---------|
    |---------|
    +---------+

Как реально это происходит:

    +---------+
    |	  |
    |	  |
    |         |
    +---------+ <--- SP  (Stack pointer)
    |	  |
    |	  |
    +---------+

Помещение в stack:
        Записать по адрессу [SP] данные
        Отнять/Прибавить SP на XX (размер данных)

Выборка из stacka:
        Прибавить/Отнять SP на XX (размер данных)
        Прочитать данные по адрессу [SP]

    +---------+
    |	  |
    |	  |
    +---------+ <--- previous SP
    | element |
    +---------+ <--- new SP
    |	  |
    +---------+

Примеры как используется стек:

Прерывание:

Вызов подпрограммы:

Вызов подпрограммы с передачей параметров:

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

  Использование стека в стековых архитектурах

Операции:

    +---------+ 	        +---------+
    |    A    |             |  A + B  |
    +---------+      +      +---------+
    |    B    |    (OP)     |    C    |
    +---------+             +---------+
    |    C    |             |         |
    +---------+
    |         |

Типичный пример JVM (Java Virtual Machine), и соответсвенно picoJava процессор.

    iadd	60
    ladd	61
    fadd	62
    dadd	63

    isub	64
    ...

    imul	68
    ...

    idiv	6c

    irem	70
    ineg	74

    ishl	78
    ishr	7A
    iushr	7C
    iand	7E
    ior	80
    ixor	82

DUP
    | A |	   | A |
    | B |	   | A |
    | C |  =>  | B |
    |xxx|      | C |
           |xxx|

OVER
    | A |      | B |
    | B |      | A |
    | C |  =>  | B |
    |xxx|      | C |
           |xxx|

    a * (a + b)

    stack:	| b |
        | a |

    OVER + *

ROT
    | A |      | C |
    | B |  =>  | B |
    | C |      | A |
    |xxx|	   |xxx|

SWAP
    | A |      | B |
    | B |  =>  | A |
    | C |      | C |
    |xxx|      |xxx|

DROP
    | A |      | B |
    | B |      | C |
    | C |  =>  |xxx|
    |xxx|

2SWAP	SWAP но пар
    A.1	B.1
    A.2     B.2
    B.1     A.1
    B.2     A.2

2DUP
2OVER
2DROP


30.3.3. ПРЕРЫВАНИЯ

THIS SECTION IS UNDER CONSTRUCTION

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

1)	Процессор выполняет действия
2)	Приходит сигнал прерывания
3)	Процессор заканчивает выполнять текущую команду
4)	Процессор выполняет прерывание
    (сохраняет PC и переходит к предопределенному адрессу.

На аппаратном уровне

    Прерывания
    /      \
  маскируемые   NMI
        (non-maskable interrupt)

Маскируемые прерывания могут быть замаскированны процессором
т.е. не будут обрабатыватся.
В процессоре существует специальный флаг IF (Interrupt Flag)
который позволяет управлять маскированием.

Вложенные прерывания:

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

IVT (Interrupt Vector Table)

Рассмотрим на примере Intel x86:

Реальный режим:

Защищенный режим (виртуальный адресс):


30.3.3.1. ИСКЛЮЧЕНИЯ

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

Например:
    Программа пыталась делить на 0
или
    Комманда имела недопустимый код операции

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

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

  Исключения на IA-32

 -----------------------------------------
Num     Description
 -----------------------------------------
0	Divide Error (division by zero)
1	Debug
2	NMI
3	Single step
4	Overlow (INTO)
5	Boundary check (BOUND)
6	Invalid opcode
7	NPX not available
8	Double fault
9
10	Invalid TSS
11	Segment not present
12	Stack fault
13	General Protection Fault
14	Page fault
15
16	Numeric error
17	Alignment check
 -----------------------------------------

  Исключения на 68K

 -----------------------------------------
Num     Description
 -----------------------------------------
0,1	Reset
2	Bus error
3	Invalid address (odd)
4	Invalid opcode
5	Division by zero
6	CHK command
7	TRAPV command
8	Privelege violution
9	Trace mode
10	FPU Emulation
11	FPU emulation
13	Coprocessor protocol violution
14	Format error
15	Uninitialized interrupt
24	Spurious Interrupt
25	Level 1 interrupt autovector
26	Level 2 interrupt autovector
27	Level 3 interrupt autovector
28	Level 4 interrupt autovector
29	Level 5 interrupt autovector
30	Level 6 interrupt autovector
31	Level 7 interrupt autovector
48	FP Branch or set on unordered condition
49	FP Unexact result
50	FP Divide by zero
51	FP Underflow
52	FP Operand Error
53	FP Overflow
54	FP Signaling NaN
55	FP Unimplemented Data Type
56	MMU Configuration Error
57	MMU Illegal Operation Error
58	MMU Access Level Violution

 -----------------------------------------

  Исключения на PowerPC

 -----------------------------------------
Vector  Description
 -----------------------------------------
00100	reset
00200	CPU control
00300	data fetch error
00400	command fetch error
00500	External interrupt
00600	Alignment check
00700	Software exception
00900	Pereodic interrupt
00C00	system call
00D00	trace
00F00	PMC1 or PMC2 overflow
01300	breakpoint
01400	SMI
 -----------------------------------------

  Исключения на IA-64

 -----------------------------------------
Vector	Description
 -----------------------------------------
0	VHPT Translation Vctor
1	Instruction TLB
2	Data TLB
3	Alt Instruction TLB
4	Alt. Data TLB
5	Data nested TLB
6	Instruction key miss
7	Data Key miss
8	Dirty bit
9	Instr. Access-bit
10	Data access-bit
11	Break instruction
12	External interrupt
20	Page not present
21	Key permission vector
22	Inst. acess rights
23	Data access rights
24	general exception
25	disabled FP_register
26	NaT consymption
27	Speculation
29	Debug
30	Unaligned reference
31	Unsupported data ref.
32	FP Fault
33	FP. Trap
34	Lower-Priv Transfer Trap
35	Taken Branch Trap
45	IA-32 exception
46	IA-32 intercept
47	IA-32 interrupt
 -----------------------------------------

  Исключения на SPARC

 -----------------------------------------
Vector	Description
 -----------------------------------------
1	Power on reset
2	Watchdog reset
3	externally initiated reset
4	software initiated reset
8	insruction access
9	instruction access MMU miss
10	illegal instruction
11	priveleged_opcode
20	FP disabled
28	division by zero
30	data access exception
34	memort address not aligned
37	priveleged acetion
41..4F	interrupt
80..9F	spill_n_normal
A0..BF	spill_n_other
C0..DF	fill_n_normal
E0..FF	fill_n_other
100.17F	trap instruction
 -----------------------------------------


30.3.4. АРХИТЕКТУРА ИНСТРУКЦИЙ

        Архитектура
        инструкций
        /   |     \
         R-R    R-M   M-M

Это архитектура для инструкций типа ALU (т.е. для вычислений)

    R-R	- может выполнятся только с регистрами (RISC)
    R-M	- один из операндов может быть памятью (CISC) x86
    M-M	- все операнды могут быть памятью      (CISC) VAX-11

  Адресность инструкции

Архитектура инструкций:
        Безадресные
        Одноадресные
        Двухадресные
        Трехадресные
        Четырехадресные

Пример безадресной инструкции:
    +----------------+
    |      DI        |	Disable Interrupts
    +----------------+	процессор сам знает где и что ему делать

Пример одноадресной инструкции:
    +----------------+
    | ADD  |   R1    |	ACC = ACC + R1
    +----------------+     (операнд приемник всегда аккумулятор) z80

Пример двухадрессной инструкции:
    +----------------+
    | ADD | R1 | R2  |	R1 = R1 + R2
    +----------------+	(операнд приемник также является одним из
                операндов)  x86

Пример трехадресной инструкции:
    +----------------+
    |ADD| R1 | R2| R3|	R1 = R2 + R3
    +----------------+	RISC

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

Пример четерехадресной инструкции
    операции работы со списками в VAX-11

Складыват два BCD числа:
ADDP4  srclen, srcaddr, dsrlen, dstaddr

Пример пятиадрессной инструкции
VAX-11

Копирует одну строку в другую с заполнением пустого места (если есть)
MOVC5   R0,R1,#0,R2,R3
MOVC5   source_string_len, source_string_address, filler,
        destination_string_len, destination_string_address

Копирует одну строку в другую транслируя все символы по таблице с заполнением
пустого места (если есть)
MOVTC	source_string_len, source_string_address, filler,
    translation_table_address, destination_string_len,
    destination_string_address

  Длинна инструкции

Команды могут иметь разный размер.
Например RISC процессоры имеют фиксированный размер команды.
CISC процессоры как правило имеют переменную длинну комманды
    (как правило от одного до 15 байтов)
Intel iAPX432 имеет границы комманд не по границе байта, а вообще побитно.

  Загрузка регистров

В случаи CISC проблем нет.

x86
    mov	eax, 012345678h

                    ; 32 bit mode
    mov	r32, i32		; 5 bytes
    mov	r32, i16		; 4 bytes
    mov	r32, si8		; 3 bytes
    mov	r32, i8			; 3 bytes

Но в RISC длинна команды ограничена.
Соответсвенно при длинне комманды 32-бит загрузить непосредственным
значением 32-битный регистр не получиться, не говоря о 64-бит

SPARC
    sethi	%hi(value), reg		     ! high 22 bit
    or	%g0, %lo(value), reg	     ! low  13 bit

SPARC
    sethi	%uhi(value), regtemp
    or	regtemp, %ulo(value), regtemp
    sllx	regtemp, 32, regtemp
    sethi	%hi(value), reg
    or	reg, regtemp, reg
    or	reg, %lo(value), reg

Наиболее интересно это сделано в транспьютерах.
Почти все простые команды в транспьютерах имеют один байт.
Перед командами с непосредственными операндами может идти префикс который добовляет
лишние 4 бита в непосредственный опреанд.

        код
PFIX	n	2n
NFIX	n	6n

LDC	n	4n
ADC	n	8n

LDC   #123	=>  PFIX      1
            PFIX      2
            LDC       3

LDC   -2        =>  NFIX      0			// Reg:   FFFFFFFF
            LDC	      #e		// shift: FFFFFFFE

И это не только для загрузки
например для переходов

J       n	0n		Jump
CALL	n	9n		Call
CJ	n	An		Conditional Jump

Таже идея используется для расширения набора команд

OPR	n	Fn		Operate

например  OR	24 FB   =>	PFIX	#4
                OPR	#B

Тоже самое для переходов
Есть команда 32-бит которая делает переход в любое  место памяти
Условный переход на меньшую дистанцию

    beq	distant_label

=>
    bneq	$1
    jmp	distant_label
$1:

THIS SECTION IS UNDER CONSTRUCTION

  Thumb

Семейство микропроцессоров ARM поддерживает Thumb - набор запакованных команд
(занимающих меньше места, чем основные команды ARM, и распаковыющихся во
время исполнения).
У процессора есть бит который показывает работает ли он в режиме Thumb, или
только в нормальном режиме.

  Выровненные команды

Учтите что поскольку в RISC процессорах команды имеют фиксированный размер и
выровнены, то младшие несколько битов в назначении команд переходов просто
не нужны

  Пример

Пример кодирования команд переходов в микропроцессоре 8080.


30.3.5. СОЗДАЕМ СВОЙ НАБОР ИНСТРУКЦИЙ

THIS SECTION IS UNDER CONSTRUCTION

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

Современные RISC-like процессоры (32-бит длинна команды)
Типичный набор тестовых аппликаций: GCC, TeX, SPICE.

Распределение смещения переходов:

Распределение смещений для обращения к данным:

Распределение величины непосредственных (immediate) операндов:

Распределение длинн данных:

Распределение условий условных переходов:


30.3.6. КОНВЕЕРИЗАЦИЯ В ПРОЦЕССОРЕ

THIS SECTION IS UNDER CONSTRUCTION

  Superscalar

  Forwarding

  Superscalar forwarding


30.4. BUS INTERFACE UNIT

BIU (Bus Interface Unit) - узел который осуществляет доступ к внешней шине.
Это ворота процессора во внешний мир.

Структура BIU:

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

Шина:
        Протокол
        Сигналы и синхронизация
        (Множество проводов)
        Электрические характеристики
        Физические и механические характеристики

Операции на шине называются транзакциями.
Основные типы транзакций - чтение и запись

Синхронный протокол - все сигналы на шине привязаны к CLK.
Асинхронный протокол.

Сигналы шины:
Типичные сигналы шины
 -----------------------------------------
Адресс    -- >	 A[0..N]        Шина адресса 	(Address Bus)
Данные	< -- >   D[0..M]        Шина данных  	(Data Bus)
Управление	 RD/WR#		Чтение/Запись   (Read/Write)
         BRDY		Готовность шины (Bus Ready)
         RESET		Сброс		(Reset)
Прерывания	 IRQ[0..J] 	Запрос прерывания  (Interrupt Request)
         IRQA[0..J] 	Подтверждение прерывания (Interrupt Acknowledge)
Арбитраж	 REQ[0..K]	Запрос арбитража (Bus Request)
         GNT[0..K]	Выдача арбитража (Bus Grant)
         BUSY		Шина занята
         LOCK		Захват шины
Разные		 CLK		Тактовый сигнал процессора (Clock)
         BCLK		Тактовый сигнал шины (Bus Clock)
         Vcc		Питание
         GND		Земля  (Ground)
 -----------------------------------------

THIS SECTION IS UNDER CONSTRUCTION

TODO: Типовые процессорные шины:
    Zilog Z80
    8088
    486

  Zilog Z80

Рассмотрим процессорную шину микропроцессора Zilog Z80:

Выборка комманды из памяти:

Обращение к памяти:

Обращение к вводу/выводу:

Арбитраж:

Обработка прерывания:


30.4.1. АРБИТРАЖ ШИНЫ

THIS SECTION IS UNDER CONSTRUCTION

  Централизовааный арбитраж

(BUSY сигнал не показан).

Каждое устройство имеет свои линии REQ (запрос шины) и GNT (предоставление
шины). Все линии сходятся к устройству арбитр шины. Оно решает кому
предоставлять шину.

Пример арбитра для централизованного арбитража
(устройство 3 наиболее приоритетное, 0 - наименее приоритетное)

  Последовательный арбитраж

(BUSY сигнал не показан).

Все устройства которые хотят шину выставляют REQ и разрывают
линию GNT.
Затем слушают GNT. То устройство у которого по GNT приходит
сигнал выиграло арбитраж.

  Арбитраж по номеру устройства

THIS SECTION IS UNDER CONSTRUCTION

Очень любят в последовательных шинах.
Когда идет начало цикла - все устройства которые хотят шину выставляют свой
код на нее. То устройство у которого номер меньше побеждает.


30.4.2. ПОВЫШЕНИЕ БЫСТРОДЕЙСТВИЯ ШИНЫ

THIS SECTION IS UNDER CONSTRUCTION

Повышение полосы пропускания шины

Повышение тактовой частоты:

Увеличение разрядности шины:

Отказ от мультиплексации шины

Пакетный режим передачи

    о Конвееризация транзакций
    о Расщепление транзакций

Расщепление транзакций
    ответ на транзакцию приходит out-of-order
    определяется по tag

    о Усовершенствованный арбитраж

Арбитраж с перекрытием
(арбитраж идет паралельно с предидущей транзакцией)

    o Арбитраж с удержанием шины
      (ведущий удерживает шину пока отсутствуют другие запросы)


30.4.3. НЕВЫРОВНЕННОЕ ОБРАЩЕНИЕ К ПАМЯТИ

Предположим что у микропроцессора 32-битная шина данных
Рассмотрим обращения к памяти:

  Байт

Байт не может быть невыровненным
Т.е. достук к нему всегда будет проходить одним циклом шины:

При чтении мы можем читать челый dword.

    +---+---+---+---+
    |   | X |   |	|
    +---+---+---+---+
    |		|
    +---------------+
      читаем все

Но при записи в память мы должны будем выставить сигналы BE (Byte Enable) для
того что бы память знала какой байт реально записывать.

                BE[3..0]	Byte address	Циклов шины
    +---+---+---+---+
+0000	| X |   |   |   |	1000		00000003h	1
    +---+---+---+---+
    +---+---+---+---+
+0000	|   | X |   |   |	0100	        00000002h       1
    +---+---+---+---+
    +---+---+---+---+
+0000	|   |   | X |   |       0010		00000001h       1
    +---+---+---+---+
    +---+---+---+---+
+0000	|   |   |   | X |	0001	        00000000h       1
    +---+---+---+---+

  Слово

При чтении слова мы уже можем попасть/можем непопасть в невыровненую память
(сразу же пишем маски для BE):
                            BE[3..0]	Word Address    Циклов шины
    +---+---+---+---+
+0000	|   |   | X | X |	0011		00000000h	1
    +---+---+---+---+
    +---+---+---+---+
+0000	|   | X | X |   |	0110		00000001h       1
    +---+---+---+---+
    +---+---+---+---+
+0000	| X | X |   |   |	1100		00000002h	1
    +---+---+---+---+

    +---+---+---+---+
+0000	| X |   |   |   |	1000		00000003h       2
    +---+---+---+---+
+0004	|   |   |   | X |       0001
    +---+---+---+---+

Таким образом для невыровненных (на границу 2) слов мы имеем 50%
невыровненных обращений к памяти.

  Двойное слово

                BE[3..0]	Dword address    Циклов шины
    +---+---+---+---+
+0000	| X | X | X | X |	1111		00000000h	1
    +---+---+---+---+

    +---+---+---+---+
+0000	| X | X | X |   |	1110		00000001h	2
    +---+---+---+---+
+0004	|   |   |   | X |       0001
    +---+---+---+---+

    +---+---+---+---+
+0000	| X | X |   |   |	1100		00000002h       2
    +---+---+---+---+
+0004	|   |   | X | X |       0011
    +---+---+---+---+

    +---+---+---+---+
+0000	| X |   |   |   | 	1000		00000003h	2
    +---+---+---+---+
+0004	|   | X | X | X |       0111
    +---+---+---+---+

Таким образом невыровненный dword - это стопудовый 2й цикл шины.

  Summary

Как правило компиляторы выравнивают данные.
Но есть ситуации когда это невозможно - например данные в сетевых пакетах,
или на storage.

Что делает процессор при обращении к невыровненной памяти:

    o Некоторые процессоры генерируют 2 такта шины
    o Некоторые процессоры имеют разные команды для
      доступа к aligned/unaligned памяти
      (соответсвенно они работают по разным алгоритмам и
       разное время).
      Если попытатся обратится к unaligned памяти aligned
      командой то возникнет aligned exception,
      в которой как правило грузят данные из unaligned памяти
      и возвращаются.
    o Есть процессоры которые вообще не обращаются к unaligned
          памяти, они генерируют exception, а программа обработчик
      сама вытаскивает байты и их соединяет.

Кроме того обращение к невыровненной памяти должно иметь
гарантированные 2 цикла шины подряд (что бы 2й процессор или аппаратура
ввода/вывода не смогли модифицировать часть данных).
Для этого как правило на шину выставляется сигнал LOCK.


30.4.4. СЕМАФОРНЫЕ ОПЕРАЦИИ И БЛОКИРОВАНИЕ ШИНЫ

THIS SECTION IS UNDER CONSTRUCTION

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

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

Semaphore
    N-арный семафор, служит для доступа к заданному числу однородных
    ресурсов

Mutex
    Взаимоисключающий доступ к ресурсам

Для этого служит сигнал LOCK (захват шины).

Как правило процессоры имею специальные команды для работы с
семафорами которые делают нужные операции
(ВНИМАНИЕ: обращение к семафорам должно идти напрямую в память а
не быть проглощено cache (как при чтении, так при записи (WriteBack)).

E.W.Dijkstra 1965

    P(S)
        if S > 0
         then S = S - 1
        else wait on S

    V(S)
        if one or more processes waits on S
        then let one process proceed
        else S = S + 1

TODO: Расписать семафорные операции
Interlocked functions
    Прибавить integer
    Присвоить integer
    Условно прибавить integer
    Условно присвоить integer
    Инкрементировать
    Декриментировать

x86:

LOCK XCHG  dest,src

    Lock Bus
    temp = dest;
    dest = src;
    src  = temp;
    Unlock Bus

LOCK XADD  dest,src
    Lock Bus
    temp = dest + src;
    src  = dest;
    dest = temp;
    Unlock Bus

LOCK CMPXCHG dest,src
    Lock Bus
    if (acc == dest)
    {
        ZF = 1;
        dest = src;
    } else {
        ZF = 0;
        acc = dest;
    }
    Unlock Bus

LOCK BTS dest, bitn
    Lock Bus
    CF = Bit{dest,bitn};
    Bit{dest,bitn} = 1;
    Unlock Bus

LOCK BTR dest, bitn
    Lock Bus
    CF = Bit{dest,bitn};
    Bit{dest,bitn} = 0;
    Unlock Bus

On x86 LOCK prefix may used with next instructions:
    ADD, ADC, AND, BTC, BTR*, BTS*, CMPXCHG*, CMPXCHG8B*,
    DEC, INC, NEG, NOT, OR,  SBB, SUB, XOR, XADD*, XCHG*
(* помечены операции с помощью которых можно реализовать мьютексы).

Есть и другой подход когда специальной командой включают LOCK на время
всех остальных операций, а потом выключают.
Плюсы:  можно реализовать сложную семафорную логику.
Минусы: так очень долго можно держать шину, а если забыть выключить
        LOCK, то даже вечно. Понятно, что это убъет bus-mastering
        устройства ввода/вывода и другие процессоры.

Mutex:

Без LOCK шины - облом:

С LOCK шины:

Захват мьютекса называется - Acquire
Освобождение мьютекса называется - Release

-------------------------------------------------------
mutex	dd	0	; Mutex in memory

acquire:
    mov	eax,1
    lock	xchg eax, mutex
    or	eax,eax
    jz	ok
    jmp	acquire		; Spin-Lock
ok:
    ....

release:
    lock mov mutex, 0	; LOCK - потому что может быть не выровненный
    ...			;        адресс

-------------------------------------------------------

На базе мьютекса можно легко делать семафоры.
Просто код который изменяет счетчик семафора должен быть защищен
мьютексом.

Например семафор на 5:
-------------------------------------------------------
Data:
    mutex
    count

Acquire(semaphore):
    Acquire(mutex)
    if (count > 5)
    {
        Release(mutex)
        return	FAILED
    }
    count = count + 1;
    Release(mutex)
    return	SUCCESS

Release(semaphore)
    Acquire(mutex)
    count = count - 1;
    Release(mutex)
-------------------------------------------------------

В принципе в однопроцессорной системе можно не заморачиватся а просто
запретить прерывания на время выполнения атомарной операции
(если конечно семафор не испульзуется каким нибудь hardware).

Spin-Lock
    пытаемся поставить мьютекс в цикле пока не поставим.

Наметилась тенденция к тому что стали появляться команды которые тянут время
до обращения к семафору, иначе постоянный опрос просто убивает шину.

Идея простая: зная адресс семафора мы можем его мониторить по шине,
          и не делать на ней операции.

    MWAIT
    MONITOR


30.4.5. ЗАПРОСЫ НА ПРЕРЫВАНИЯ

THIS SECTION IS UNDER CONSTRUCTION

Как правило обработкой запровов на прерывания, их приоретизацией занимается
контролер прерываний, который потом передает вектор для прерывания в процессор.

    Запускается по изменению линии запроса на прерывание
    1) Если прерывание маскированно, то выходим
    2) Если есть более приоритетные прерывания в обработке
       ставим в очередь.
    3) Вызываем прерывание у процессора

    Прерывания
    /       \
  по фронту     по уровню

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

Прерывание по фронту:

Прерывание по уровню:

Контроллер прерываний
PIC
APIC

Специальная выделенная шина для прерываний


30.5. FLOATING POINT UNIT

THIS SECTION IS UNDER CONSTRUCTION

  FP сумматор

  FP умножитель

  Нормализация

Для выполнения операций выполняют процедуру нормализации сущность которой
сводится к приведению мантисс к одной (большей) экспоненте.

Соответсвенно бывает pre- и post- нормализация, до и после выполнения
операции соответственно.

Кроме того для уменьшения потери точности как правило к мантиссе снизу
добавляют еще один бит (sticky bit).

  FP делитель

  FP блок для квадратного корня

  Вычисление сложных функций

Интерполяция

Конвертор из целых в FP.

Все очень просто - шифратор
Пример для конвертации положительных 11-битных целых в FP формат вида:

      4    3
    +----+---+
    |  M | E |
    +----+---+

    0*2^0 ....  (2^4 - 1) *  2^7

    library IEEE;
    use IEEE.std_logic_1164.all;

    entity xptofp is
        port (
            B : in std_logic_vector(10 down to 0); -- Fixed point vector
            M : out std_logic_vector(3 downto 0);  -- Mantissa
            E : out std_logic_vector(2 downto 0)  -- Exponent
        );
    end xptofp;

    architecture rtl of xptofp is
    begin
        process(B)
        begin
            if    B(10) = '1' then M <= B(10 downto 7); E <= "111";
            elsif B(9)  = '1' then M <= B(9  downto 6); E <= "110";
            elsif B(8)  = '1' then M <= B(8  downto 5); E <= "101";
            elsif B(7)  = '1' then M <= B(7  downto 4); E <= "100";
            elsif B(6)  = '1' then M <= B(6  downto 3); E <= "011";
            elsif B(5)  = '1' then M <= B(5  downto 2); E <= "010";
            elsif B(4)  = '1' then M <= B(4  downto 1); E <= "001";
            else                   M <= B(3  downto 0); E <= "000";
            end if;
        end process;
    end rtl;

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

    ----------------------------------------------------------
    Число  В бинарном 		  FP
    ----------------------------------------------------------
    0       00000000 	0 00000000 00000000000000000000000
    1       00000001	0 01111111 00000000000000000000000
    2-3     0000001x	0 10000000 x0000000000000000000000
    4-7     000001xx	0 10000001 xx000000000000000000000
    8-15    00001xxx	0 10000010 xxx00000000000000000000
    16-31   0001xxxx	0 10000011 xxxx0000000000000000000
    32-63   001xxxxx	0 10000100 xxxxx000000000000000000
    64-127  01xxxxxx	0 10000101 xxxxxx00000000000000000
    128-255 1xxxxxxx	0 10000110 xxxxxxx0000000000000000
    ----------------------------------------------------------

Блок для вычисления сложных функций

    Смотри секцию про числа с плавающей точкой.

  LNS FP Unit


30.5.1. FP UNIT CONTROL AND STATUS REGISTERS

THIS SECTION IS UNDER CONSTRUCTION

  Состояние FP

Типичные флаги операций с плавающей точкой:
    Overlow
    Underflow
    Division by zero
    Invalid operation (операнд(ы) NaNs)
    Inexact   (потеря точности за счет денормализации)
    Флаги сравнения
        Greater
        Less
        Equal
        Unordered (например сравниваем число с NaN)

  Управление FP

    В первую очередь - это режимы округления
        к ближайшему
        к нулю
        к +бесконечности
        к -бесконечности

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

  x86

Status word:

  Alpha

FPC:

    ---------------------------------------
    DNOS	Denormalized operand status
    INES	Inexact
    UNFS	Underflow
    OVFS	Overflow
    DZES	Division by zero
    INVS	Invalid operation
    ---------------------------------------

  HP-PA

FPS:

    ------------------------------------
    RM 	Round mode
            0  to nearest
            1  toward zero
            2  toward +infinity
            3  toward -infinity
    V  	Invalid operation
    Z  	Division-by-zero
    O  	Overflow
    U  	Underflow
    I  	Inexact result
    -------------------------------------

  MIPS

FCSR:

  PowerPC

FPSCR:

    ---------------------------------------
    FX	FP exception summary
    FEX	FP enable exception summary
    VX	invalid operation exception
    OX	overflow exception
    UX	underflow exception
    ZX	divide by zero exception
    XX	inexact exception
    VXSNAN	invalid operation for SNaN
    VXISI	infinity - infinify
    VXIDI	infinity / infinity
    VXZDZ	0/0
    VXIMZ	0*infinity
    VXVC	invalid compare
    FR	fraction rounded
    FI	inexact
    FPRF	fp result flags
        15 class descriptor
        16	<
        17	>
        18	==
        19	Unordered or NaN
    VXCVI	invalid integer convert
    VE	enable invalid
    OE	enable overflow
    UE	enable underflow
    ZE	enable zero divide
    XE	enable inexact
    RN	round
            00	nearest
            01	toward zero
            10	toward +infinity
            11	toward -infinity
    ---------------------------------------

  SPARC

FSR:

    ---------------------------
    fccn	0	Equal
        1	Less
        2	Greater
        3	Unordered
    ---------------------------

    ---------------------------
    RD	0	nearest
        1	toward 0
        2	toward +infinity
        3	toward -infinity
    ----------------------------

    --------------------------------------------
    Trap enable	    NVM  OFM  UDM  DZM  NXM
    Trap occured        nva  ofa  ufa  dza  nxa
    Current	exception   nvc	 ofc  ufc  dzc  nxc
    --------------------------------------------


30.6. MULTIMEDIA UNIT

The Multimedia Unit is open from 9.00. am to 5.00 pm on weekdays.
            Some text from Inet.

THIS SECTION IS UNDER CONSTRUCTION

THIS SECTION IS UNDER CONSTRUCTION

Стали появляться мультемедийные наборы инструкций:

    x86	MMX, SSE, SSE2
    Alpha	MVI
    MIPS	MDMX
    PowerPC AltiVec
    HP-PA2
    IA64

Векторные операции:
    сначала целочисленные
    потом FP

Multimedia Unit представляет из себя векторное ALU,
как правило еще и хорошо конвееризированное.
Register File для Multimedia регистров как правило тоже выносят сюда.

  Форматы векторов

Целочисленные вектора:

    ---------------------------------------------
    Размер	Организация	Варианты
    ---------------------------------------------
    8	8x  1 byte	Signed/Unsigned, Binary/Saturation
    8	4x  2 bytes
    8	2x  4 bytes
    16	16x 1 byte
    16	8x  2 bytes
    16	4x  4 bytes
    16	2x  8 bytes
    ---------------------------------------------

    ---------------------------------------------
    Размер	Организация
    ---------------------------------------------
    8	2 x Single
    16	4 x Single
    16	2 x Double
    ---------------------------------------------

  Векторные операции

Типовые векторные операции
        Сложение (3 формы)
    Вычитание (3 формы)
    Bitwize logical
    Maximum/Minimum

Скалярная операция:

Делает тоже самое что векторная операция только
с младшим элементом вектора

Сдвиги

Сдвиг задается один для всех

Сдвиг задается отдельно для каждого элемента вектора

Паралельное сравнение

Sum of Absolute Differnece

Multiply and Accumulate

Рельно есть 2 возможных типа для таких операций:
Multiply-accumulate		2 округления  (MAC)
Fused Multiply-accumulate       1 округление  (FMAC)
Как правило в Multimedia Units используют FMAC - он быстрее.

Shuffle:

Unpack:

Ассиметричные операции:

Горизонтальный сдвиг:

  MMU

Блок-схема целочисленного MMU:

По сравнение с обычным ALU MMU отличается не только векторизацией но и
дополнительным набором комманд:

арифметика с насыщением
    в отличии от обычных вычислений насыщение знаковое и беззнаковое
    отличаются друг от друга
        Signed Saturation
        Unsigned saturation

    Average sub
    Sum of Absolute difference
    Shuffle, Pack/Unpack
    Min/Max

  Partitional ALU

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

  Арифметика с насыщением:

Add Unsigned saturated:

Sub Unsigned saturated:

Add Signed Saturated:

Sub Signed Saturated:

Как правило реализуются дополнительными схемами на выходе сумматора,
например:

  Вычисление Maximum/Minumum

Unsigned Maximum:

Unsigned Minimum:

Signed Maximum:

Signed Minimum:

  Shuffle Unit

ОБЯЗАТЕЛЬНО ПРОЧИТАЙТЕ СЕКЦИЮ 35.2.3. ДО ТОГО КАК ЧИТАТЬ СЛЕДУЩУЮ СЕКЦИЮ


30.6.1. ОСОБЕННОСТИ ПРОГРАММИРОВАНИЯ MULTIMEDIA UNIT

  Константы

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

  0

Основа формирования константы 0 - это векторный XOR одного операнда с самим собой.
Поскольку:
    0 xor 0 = 0
и	1 xor 1 = 0
то после выполнения этой операции мы получим 0 в векторном регистре.

  -1

Multimedia Unit имеет команды паралельного сравнения, которые устанавливают результатирующий
элемент вектора в 1...1, если условие выполняется, или в 0...0, если условие не выполняется.
Мы можем использовать вариант VCMPEQ - проверяющий на равенство используя в качестве
параметров один и тот же операнд два раза.
Поскольку X = X, то в результате весь векторный регистр будет содержать одни 11..11,
что означает -1 для каждого элемента вектора.

  1

Получение единицы основано на простом соотношении:

    1 = 0 - (-1)

а получать 0 и -1 мы уже умеем.

  -X

Основа для получения -X:

    -X = 0 - X

ноль мы тоже умеем получать.

  NOT

                     _
Основа для получения X - операция XOR
Поскольку:
        0  xor 1 = 1
    1  xor 1 = 0

то получаем:
    _
    X = X xor (-1)

а -1 мы тоже умеем получать.

  ABS

Для вычислений часто приходиться получать абсолютную величину числа (модуль).
Принцип вычисления модуля базируется на векторной операции VMAX - которая возвращает
максимальный из своих операндов.

Собственно:

    |X| =  X, если X >= 0
          -X, если X <  0

или
    |X| = MAX(X, -X)

собсвенно -X мы вычислять умеем:  -X = 0 - X

  NABS

То же самое действует для вычисления negative absolute value, только используется
не VMAX, а VMIN

    -|X| =  X, если X  < 0
           -X, если X  >= 0
или
    -|X| = MIN(X, -X)

собственно результат мы получили.

  CMOV

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

Пример вычисляет:

    destination[i] = (source1[i] > source2[i])? source1[i] : source2[i]

При этом считам что:
    AF, C>G, D source2[i])? -1 : 0

Затем отрицательные результаты сравнения для первого операнда маскируются по маске

    temp1[i] = source1[i] & mask[i]

а для второго операнда по инверсной маске

    temp2[i] = source2[i] & (~mask[i])

что означает:
    temp1[i] = (source1[i] > source2[i])? source1[i] : 0
и	temp2[i] = (source1[i] > source2[i])?  0         : source[2]

делая
    destination[i] = temp1[i] | temp2[i]

получаем то что мы и хотели:
    destination[i] = (source1[i] > source2[i])? source1[i] : source2[i]

4 векторных команды и никаких ветвлений

Самое интересное, что таже техника используется и для FP векторов.
Поэтому есть команды типа Vector Parallel Compare и ЛОГИЧЕСКИЕ ВЕКТОРНЫЕ ОПЕРАЦИИ
для FP векторов, даже если FP вектор unit - является отдельным и не в состоянии
хранить integer data. Но возможность conditional move все искупает.

  Bound

С помощью MAX и MIN можно делать насыщение по любым границам,
таким образом держа результаты в нужном диапазоне


35. ОБЗОР СОВРЕМЕННЫХ МИКРОПРОЦЕССОРОВ

В этой секции мы рассмотрим характеристики наиболее популярных
семейств микропроцессоров общего назначения:

    o  Intel IA-32
    o  Intel IA-64 (Itanium)
    o  Motorola 68K
    o  DEC Alpha
    o  MIPS
    o  PowerPC
    o  HP-PA
    o  SPARC
    o  ARM

 -----------------------------------------------------
    Endian	Address	TypicalPageSize	AddressSpace
 -----------------------------------------------------
IA-64	Little	64	4/8/16/64K	32PB
IA-32	Little	32	4K		4G
HP-PA	Big	32	4K		4G
Alpha	Little	64	8K		8T
PowerPC	Big	32	4K		4G
SPARCv9	Big	64	8K		8T
 -----------------------------------------------------


35.1.1. DEC ALPHA

THIS SECTION IS UNDER CONSTRUCTION

DEC Alpha 21064 CPU:

Блок схемы CPU:
21064:

21164:

21264 EV67:

  Эволюция

    21064 ['92] ----- > 21064a ['94], 21066a ['93]
     |
     V
    21164 ['94] ----- > 21164PC ['97], 21164a ['96]
     |
     V
    21264  EV67 ['98]
     |
     V
    21264a  EV68 ['99]
     |
     V
    21364

  Регистры

Целочисленные:
    r0-r31	размер 64-бита
        r29	gp	(Global pointer)
        r30	sp	Stack pointer
        r31	0
    Direction:	< =====
        OP	rs1,rs2,rd

    Memory Access:	offset(reg)
            lda	sp,-16(sp)
    Immediate Values: num
            addq	r1,-10,r3
    Byte Order:	Big-endian?
    Instruction Len: fixed 32-bit

Плавающей точки:
    f0-f31	размер 64-бита
        f31	0.0

Форматы обращения к памяти:
    disp(Rx)

  Формат инструкций

  Особенности

        Типичный RISC процессор
    Little-Endian
    Команды имеют фиксированную длинну 32-бита.
    Не имеет команды деления
    Расширения Multimedia: MVI (21264) integer


35.1.2. MOTOROLA 68K

THIS SECTION IS UNDER CONSTRUCTION

Motorola 68020:

Motoroal 68060:

68000:

68020:

68040:

68060:

  Эволюция

    68000 ['79?]
      |
      V
    68020 ['85]
      |
      V
    68030
      |
      V
    68040 ['89]
      |
      V
    68060 ['93]

  Регистры

    d0..d7			(Data Registers)
    a0..a6			(Address Registers)
    a7  usp  ssp		(User Stack Pointer/Supervisor stack pointer)
    pc
    fp0..fp7		(FP on MC68040 etc or on MC68881 etc)
    Zero Register:	None
    Direction:	------------->
        OP	rs1,rs2,rd

    Memory Access:
        add	d6,d0
        add	(a4)+,d2
        add	(20,a4,d5),d0
    Immediate Operands:
        add	#&5,d5
            (Note:		5	- Decimal (Default)
                       &5	- Decimal
                     %101	- Binary
                       @5	- Octal
                       $5	- Hexdecimal	)
    Byte Order:	Big-endian
    Command Len:	Mainly 16-bit
    Generations:
        68000	- main CPU (MUL/DIV only 16->32,32->16)
        68020	- + normal MUL/DIV
    ---------------------------------------------------------------

Регистр флагов (CCR)
    XNZVC
        C - Carry
        V - Overflow
        Z - Zero
        N - Negative
        X - Extend (set as C for arithmetic operation only,
                otherwize unchanged)

    15	Tracing
    13	Supervisor
    10..8	Interrupt mask I
    4	X
    3	N
    2	Z
    1	V
    0	C

Форматы обращения к памяти:
        offset
        (An)
        (An)+
        -(An)
        (disp16,An)
        (disp8,An,Xn)
        (An,Rk).W		size 16
        (An,Rk).L		size 32
        (disp16,PC)
        (disp8,PC,Xn)

  Особенности

    CISC микропроцессор
    Big-endian
    Расширения Multimedia: нет


35.1.3. POWER PC

THIS SECTION IS UNDER CONSTRUCTION

PowerPC 601:

Power PC 602:

Power PC 604e:

G4:

  Эволюция

Power PC
(32-bit):
        601 ['93] --- > 601v ['94]  ---> 602 ['95]
             |
         V
        603  ['94]--- > 603e ['95], 603q ['96]
         |
         V
        604  ['94] --- > 604e ['96]
         |
         V
        740 (G3) ['97] --> 704 ['97]
         |
         V
        750 (G3) ['97]
         |
         V
        7400 (G4) ['99]		+AltiVec
         |
         V
        74XX (G4+)  ['01]

Power PC
(64-bit):
        620 ['95]
         |
         V
        630 (POWER 3) ['98]
         |
         V
        970  G5 ['99]

  Регистры

 -----------------------------------------------------------------
    r0  - r31	Integer Registers
    fr0 - fr32	Floating Point Register
    sp
    cr		condition register
    fpscr		fp status & conditional reg.
    xer  (spr1)
    lr   (spr8)	link register
    ctr  (spr9)	count register

    Zero register:
    Direction:	------------->
        PPC	OP	rd,rs1,rs2
    Memory access:	offset(base)
            l	r31,-4(SP)
    Immediate values: num
            mov	1,r4
    Byte order:	Big endian
    Instruction Len:	fixed 32-bit
     -----------------------------------------------------------------

Форматы обращения к памяти:
        disp16(Rb)
        disp16(Rb)	with update Rb to Rb+disp16
                (this select by menmonic)
        Ra,Rb		with update Ra to Ra+Rb
        Ra,Rb

  Особенности

    RISC микропроцессор
    Big-endian
    Расширения Multimedia: AltiVec (G4) integer/fp


35.1.4. MIPS

THIS SECTION IS UNDER CONSTRUCTION

IDT MIPS R4600:

MIPS 20K:

  Эволюция

32-bit:
    R2000 ['86]	MIPS I
      |
      V
    R3000 ['88]	MIPS II
      |
      V
    R6000 ['91]

64-bit:
        R4000 ['92] ------- > R4200 ['93] ---- > R4300i ['95]
          |
          V
            R4400 ['92]  ------- > R4600 ['94]  ---- > R4700 ['95]
          |
          V
        R5000 ['96]  ------- > R7000 ['97]
          |
          V
        R8000  ['94]
          |
          V
        R10000 ['96]
          |
          V
        R12000 ['98]
          |
          V
        R20000 ['00-'01?]

TO DO: Показать где MIPS IV и MIPS V

  Регистры

 -----------------------------------------------------------------
    $0		Zero, uncgangable
    $1		Reserved for assembler
    $2-$3		Function Return value
    $4-$7		First few procedure arguments
    $8-$15		Scracth register
    $16-$23		register variables
    $24-$25		Scratch register
    $26-$27		Reserved for operating system
    $28		Global pointer (also called $gp)
    $29		Stack pointer  (also called $sp)
    $30		registers variable
    $31		procedure return address
    $f0-$f2		function return value
    $f4-$f10	scratch register
    $f12-$f14	First two procedure arguments
    $f16-$f18	Scratch registers
    $f20-$f30	Register variables
    Zero Register:	$0
    Direction:
            <----------
    Memory Access:		offset(base)
            la	$2,x($4)
    Intermediate Values: num  0xnum
            and	$1,$5,0xff

    Generations:
            MIPS I, II 	- 32-bit
            MIPS III, IV	- 64-bit

     -----------------------------------------------------------------

Форматы обращения к памяти:
        disp16(Rb)   integer
        Ri(Rb)       only FP.

  Особенности

    RISC микропроцессор
    Расширения Multimedia: MDMX - integer, MIPS V - fp


35.1.5. SPARC

THIS SECTION IS UNDER CONSTRUCTION

UltraSPARC III:

MicroSPARC IIep:

SuperSPARC II:

UltraSPARC I:

UltraSPARC IIi:

  Эволюция

SPARC V8
(32-bit):
    Micro  ['91]
     |
     V
    Micro II ['94]  --- > Micro III ['97]

    Super  ['92] ---- > Hyper ['93]
     |
     V
    Super II ['95]

SPARC V9:
(64-bit):
    Ultra  ['95]
     |
     V
    Ultra+ ['95] ----- > Turbo ['96]
     |
     V
    Ultra II ['96]
     |
     V
    Ultra IIi ['98]
     |
     V
    Ultra III ['00]
     |
     V
    Ultra IV  ['04]

  Регистры

 -----------------------------------------------------------------
    %r0-%r7	  %g0-%g7  Fixed global registers (Not stacked)
    %r8-%r15  %o0-%o7  Outgoing arguments (stacked)
    %r16-%r23 %l0-%l7  Locales. (stacked)
    %r24-%r31 %i0-%i7  Incoming arguments (stacked)
    %f0-%f31	   Floating point registers
               (DP only even:  i.e. %f0, %f2,...%f62)
               (QP only 4align: i.e. %f0, %f4,...%f60)
    %sp		   equ (%o6)	Stack pointer
    %fp		   equ (%i6)	Frame pointer
    Direction:

    Memory Access:	[regoffset]
            ld	[%o2-12],%o3
    Immediate Values: num
            add	%l0,4,%l0
    Generations:
        SPARC V8	-	32-bit
        SPARC V9	-	64-bit
     -----------------------------------------------------------------

Форматы обращения к памяти:
        disp13(Rs)
        Rx(Rs)

  Особенности

    RISC микропроцессор
    Big-endian
    Регистровые окна
    Расширения Multimedia: VIS


35.1.6. HP-PA

THIS SECTION IS UNDER CONSTRUCTION

PA7100:

  Эволюция

HP-PA 1.0/1.1:
(32-bit)
    7000 ['89]
     |
     V
    7100 ['92] ------ > 7150 ['94], 7100LC ['94]
     |
     V
    7200 ['94]  ----- >  7300LC ['96]

HP-PA 2.0:
(64-bit)
    8000 ['96]
     |
     V
    8200 ['97]
         |
     V
    8500 ['98]
     |
     V
    8600 ['00]

  Регистры

 -----------------------------------------------------------------
    %r0-%r31	Integer Registers
    %r0		Permanent zero
    %r1		Target for ADDIL
    %r31		Link register for BLE
    %fr0-%fr31	Floating Point registers
    %fr0-%fr3	Status & Exception Registers
    %fr4-%fr31	Possible to use  registers
    %fr0H-%fr31H	F.P. Registers (High Part)
    %fr0L-%fr31L	F.P. Registers (Low Part)
    Zero Register:
    Direction:
    Memory Access:
    Immediate Values:
    Byte Order:             ?
    Instruction Len:	fixed 32-bit
     -----------------------------------------------------------------

Форматы обращения к памяти:
        disp16/14(Rb)				Format Long displayment
        disp12(Rb)	for words
        disp11(Rb)	for double words
                            Short displayment
        disp5(Rb)	no modify
                post modify
                pre modify
                                Indexed
        (Rb,Rx)		no shift, no modify base
                no shift, modify base
                shift index by data size,no modify base
                shift index by data size, modify base

  Особенности

    Все команды являются условными
    Расширения Multimedia: HP-PA 2.0


35.1.7. IA-32 (X86)

THIS SECTION IS UNDER CONSTRUCTION

8086:

80386DX:

80486SX:

Pentium:

  Эволюция

[только Intel]
    8086 ['78] --- > 8088 ['79]
     |
     V
    80286 ['82]
     |
     V
IA32:	80386DX ['85] -- > 80386SX ['88]
     |
     V
    80486 ['89] -- > 80486SX ['91]
     |
     V
       Pentium  ['93] --> Pentum w/MMX ['97]
     |
     V
      Pentium Pro ['95]
     |
     V
      Pentium II ['97] --> Celeron
     |
     V
      Pentium III ['99] --> Pentium M
     |
     V
      Pentium 4 ['00]

  Регистры

 -----------------------------------------------------------------
    eax	ax	al
    ebx	bx	bl
    ecx	cx	cl
    edx	dx	dl
    esi	si
    edi	di
    ebp	bp		<- Frame pointer
    esp	sp
    Note: Floating Point operation processed specially on x86, 'cos
          of FP. Stack architecture.
          But also possible to use MMX2 for single operations.
    Zero Register:	None
    Direction:
            <------------
    Memory Access:
        mov	ebx,[eax+ecx+esi*2]
    Immediately Data
        add	ah,23h
    Byte order:		Little-endian
    Instruction Len:	variable 1-15 bytes long
    Main Generations:
    8086+			16-bit
    386+			32-bit

    Регистр флагов:
        13..12	IOPL
        9	IF
        8	TF
        THIS SECTION IS UNDER CONSTRUCTION
    --------------------------------------------------------------

Форматы обращения к памяти:
    на самом деле архитектура сегментная поэтому зависит от регистра

16bit memory (No 32 bit memory address prefix):
MMM	Default	MM  Field
Field	Sreg	00		01		10		11=MMM is reg
000	DS	[BX+SI]		[BX+SI+O8]	[BX+SI+O16]
001	DS	[BX+DI]		[BX+DI+O8]	[BX+SI+O16]
010	SS	[BP+SI]		[BP+SI+O8]	[BP+SI+O16]
011	SS	[BP+DI]		[BP+DI+O8]	[BP+DI+O16]
100	DS	[SI]		[SI+O8]		[SI+O16]
101	DS	[DI]		[DI+O8]		[DI+O16]
110	SS	[O16]		[BP+O8]		[BP+O16]
111	DS	[BX]		[BX+O8]		[BX+O16]
Note: MMM=110,MM=00 Default Sreg is DS !!!!

32bit memory (Has 67h 32 bit memory address prefix):
MMM	Default	MM  Field
Field	Sreg	00		01		10		11=MMM is reg
000	DS	[EAX]		[EAX+O8]	[EAX+O32]
001	DS	[ECX]		[ECX+O8]	[ECX+O32]
010	DS	[EDX]		[EDX+O8]	[EDX+O32]
011	DS	[EBX]		[EBX+O8]	[EBX+O32]
100 see SIB	[SIB]		[SIB+O8]	[SIB+O32]
101	SS	[O32]		[EBP+O8]	[EBP+O32]
110	DS	[ESI]		[ESI+O8]	[ESI+O32]
111	DS	[EDI]		[EDI+O8]	[EDI+O32]
Note: MMM=110,MM=00 Default Sreg is DS !!!!

SIB is (Scale/Base/Index):
  SS  BBB  III
Note: SIB address calculated as :
        =+*(2^(Scale))

Field	Default	Base
BBB     Sreg	Register	Note
000	DS	EAX
001	DS	ECX
010	DS	EDX
011	DS	EBX
100	SS	ESP
101	DS	O32		If MM=00   (Postbyte)
    SS	EBP		If MM<>00  (Postbyte)
110	DS	ESI
111	DS	EDI

Field	Index
III	register	Note
000	EAX
001	ECX
010	EDX
011	EBX
100			Never Index SS can be 00
101	EBP
110	ESI
111	EDI

Field	Scale coefficient
SS      =2^(SS)
00	1
01	2
10	4
11	8

  Особенности

    CISC микропроцессор с частичной RISC архитектурой
    Little-endian
    Самый сложный набор инструкций из всех
    Расширения Multimedia: MMX,SSE,SSE2,SSE3 {3DNow!}


35.1.7.2. X86-64 (AMD64)

THIS SECTION IS UNDER CONSTRUCTION

AMD:
    Opteron  ['03]  --- > Athlon64 ['03]

Intel:
    Pentium 4 with EM64T ['04]

  Регистры

 -----------------------------------------------------------------
    rax	eax	ax	al
    rbx	ebx	bx	bl
    rcx	ecx	cx	cl
    rdx	edx	dx	dl
    rsi	esi	si	sil
    rdi	edi	di   	dil
    rbp	ebp	bp	bpl	< - Frame pointer
    rsp	esp	sp	spl	< - Stack pointer
    r8	r8d	r8w	r8b
    r9	r9d	r9w	r9b
    r10	r10d	r10w	r10b
    r11	r11d	r11w	r11b
    r12	r12d	r12w	r12b
    r13	r13d	r13w	r13b
    r14	r14d	r14w	r14b
    r15	r15d	r15w	r15b

    Zero Register:	None
    Direction:
            <------------
    Memory Access:
        mov	rax,[rip+1234h]
    Immediately Data
        add	ah,23h
    Byte order:		Little-endian
    Instruction Len:	variable 1-15 bytes long
    Main Generations:
        AMD64		Base set + 3DNow!
        I64ME		Base set + SSE3
    --------------------------------------------------------------
Форматы обращения к памяти:

Format of Postbyte:

  MM RRR MMM

MM  - Memory addresing mode
RRR - Register operand address		(high bit is REX.R)
MMM - Memory operand address		(high bit is REX.B)

64bit memory (default)
MMM	Default	MM  Field
Field	00		01		10		11=MMM is reg
0000	[RAX]		[RAX+O8]	[RAX+O32]
0001	[RCX]		[RCX+O8]	[RCX+O32]
0010	[RDX]		[RDX+O8]	[RDX+O32]
0011	[RBX]		[RBX+O8]	[RBX+O32]
0100 	[SIB]		[SIB+O8]	[SIB+O32]
0101	[RIP+O32]	[RBP+O8]	[RBP+O32]
0110	[RSI]		[RSI+O8]	[RSI+O32]
0111	[RDI]		[RDI+O8]	[RDI+O32]
1000	[R8]		[R8+O8]		[R8+O32]
1001	[R9]		[R9+O8]		[R9+O32]
1010	[R10]		[R10+O8]	[R10+O32]
1011	[R11]		[R11+O8]	[R11+O32]
1100	[R12]		[R12+O8]	[R12+O32]
1101	[R13]		[R13+O8]	[R13+O32]
1110	[R14]		[R14+O8]	[R14+O32]
1111	[R15]		[R15+O8]	[R15+O32]

32bit memory (Has 67h 32 bit memory address prefix):
MMM	Default	MM  Field
Field	00		01		10		11=MMM is reg
0000	[EAX]		[EAX+O8]	[EAX+O32]
0001	[ECX]		[ECX+O8]	[ECX+O32]
0010	[EDX]		[EDX+O8]	[EDX+O32]
0011	[EBX]		[EBX+O8]	[EBX+O32]
0100 	[SIB]		[SIB+O8]	[SIB+O32]
0101	[EIP+O32]	[EBP+O8]	[EBP+O32]
0110	[ESI]		[ESI+O8]	[ESI+O32]
0111	[EDI]		[EDI+O8]	[EDI+O32]
1000	[R8D]		[R8D+O8]	[R8D+O32]
1001	[R9D]		[R9D+O8]	[R9D+O32]
1010	[R10D]		[R10D+O8]	[R10D+O32]
1011	[R11D]		[R11D+O8]	[R11D+O32]
1100	[R12D]		[R12D+O8]	[R12D+O32]
1101	[R13D]		[R13D+O8]	[R13D+O32]
1110	[R14D]		[R14D+O8]	[R14D+O32]
1111	[R15D]		[R15D+O8]	[R15D+O32]

Here we show only 64-bit SIB, 32-bit is same but DWORD registers,
instead of QWORD.

SIB is (Scale/Base/Index):
  SS  BBB  III
Note: SIB address calculated as :
        =+*(2^(Scale))
    BBB  (high bit is REX.B)
    III  (high bit is REX.X

Field	Base
BBB     Register	Note
0000	RAX
0001	RCX
0010	RDX
0011	RBX
0100	RSP
0101	RIP+O32		If MM=00   (Postbyte)
    RBP		If MM<>00  (Postbyte)
0110	RSI
0111	RDI
1000	R8
1001	R9
1010    R10
1011    R11
1100    R12
1101    R13
1110    R14
1111    R15

Field	Index
III	register	Note
0000	RAX
0001	RCX
0010	RDX
0011	RBX
0100			Never Index SS can be 00
0101	RBP
0110	RSI
0111	RDI
1000    R8
1001    R9
1010    R10
1011    R11
1100    R12
1101    R13
1110    R14
1111    R15

Field	Scale coefficient
SS      =2^(SS)
00	1
01	2
10	4
11	8

  Особенности

    64-битное расширение x86 (IA-32) архитектуры
    Расширения Multimedia: MMX,SSE,SSE2 {3DNow!/SSE3}


35.1.8. IA-64

THIS SECTION IS UNDER CONSTRUCTION

  Эволюция

IA-64:
    Itanium  ['00]
      |
      V
    Itanium 2 ['02]

  Регистры

    --------------------------------------------------------------
Integer
   (static subset)
    r0			Permnent Zero Register
    r1	gp		Global Pointer (Pointer to Global Address Seg)
    r2-r3			(use with 22bit immediate add)
    r4-r7
    r8..r11	ret0..ret3	Integer Returns Values from procedures
    r12	sp		Stack Pointer
    r13	tp		Thread Pointer
    r14..r31
   (stacked subset)
    r32..r39  in0..in7	Incoming Arguments
    r32..r127		(Using Renaming)

Floating-Point
     (static subset)
    f0			Permanent 0.0
    f1			Permanent 1.0
    f2..f7
    f8..f15	farg0..farg7  fret0..fret7 FP.Params/Returns
    f16..f31
     (stacked subset)
    f32..f127
Branch
    b0	rp		Return Pointer
    b1..b7

Predicate Regisers (Tags = 1bit).
    p0			Always 1
    p1..p63
    Zero register:	r0 f0
    Direction:	<-------------
    Memory Access:
        mov	r4 = [r5]
    Immediate operands:
        movl	r5,345h
    Byte order:	Little-endian possible too for data,
            Big-endian possible for data.
    Command Length:
            Command pairing in bindle.
            Length of bindle is 16 bytes.
            Command length is xx bits.
    Main Generation
            Itanium	- IA64 1.0
    ---------------------------------------------------------------
Форматы обращения к памяти:
        [Rb]		no update
        [Rb],Rx		update base
        [Rb],imm9	update base

  Особенности

    EPIC микропроцессор с VLIW
    Отсутствуют команды умножения и деления
    Расширения Multimedia: IA-64 уже содержит multimedia комманды
    Little-endian


35.1.9. ARM

THIS SECTION IS UNDER CONSTRUCTION

  Эволюция

ARM:
    610 ['93]
     |
     V
    710 ['94]
     |
     V
    810 ['96]

Strong ARM:
    SA-110  ['96]
     |
     V
    SA-1100 ['97]

Thumb:
    940T	['98]
     |
     V
    1020T   ['00]

  Регистры

---------------------------------------------------------------
    r0..r13		General Purpose Registers
    r14		Link Register (Here write links)
    r15		Program Countter
    Generations:

        ARM architecture 2
                MUL
        ARM architecture 4
                UMULL/UMLAL/SMULL/SMLAL
                Load/Store Signed Bytte
                Load/Store Halfword

    Регистр флагов:
        31	N
        30	Z
        29	C
        28	V
        7..6	Interrupt disable
        4..0	processor mode

Форматы обращения к памяти:

    [Rn,#offset12]
    [Rn,Rm]

    [Rn,#offset12]!		preindexing + update
    [Rn],#offset12		postindexing + update
                        EA= Rn,	Rn <- Rn + Update

    [Rb,+-Rm,shift]		preindex
    [Rn,+-Rm,shift]!	preindeing + update
    [Rn],+-Rm,shift		EA = Rn, Rn <- Rn + Update

  Особенности

    Самое популярное ядро для встроеных приложений
    Имеет вариант Thumb с короткими инструкциями.


35.2. НАБОРЫ КОМАНД

THIS SECTION IS UNDER CONSTRUCTION

В данной секции мы будем детально рассматривать наборы команд
основных современных микропроцесоров:

    o	Intel	x86
    o	Digital	Alpha
    o	MIPS
    o	Power PC
    o	Motorola MC68xxx
    o	SPARC V9
    o	HP PA-RISC
    o	Intel  ia64
    ----------------------------- местами как дополнение:
    o	Zilog z80
    o	Intel i51
    o	Java Virtual Machine
    o	ARM
    o	SuperH 4


35.2.1 ЦЕЛОЧИСЛЕННЫЕ КОМАНДЫ

В этой секции мы будем рассматривать целочисленные команды:

Integer core instruction include:
    o  Arithmetical (incl. multiply/divide)
    o  Logical
    o  Shifts and Rotates
    o  Integer Data loading/storing
    o  Integer data types convertion
    o  Compares and Conditional jumps
    o  Calls, Returns and Unconditional jumps
    o  Conditional set and moves
    o  Bit and bit string routines
    o  Stack manipulating instruction

Для команд рассматривается максимальная форма, то есть например сложение:

    destination = source1 + source2

рассматривается в полном варианте как 3 операндная.
Хотя например в двухоперандных архитектурах - типа x86, она
выраждается в частный случай

    destination = destination + source

Как читать наши таблицы

        +------------------ Процессор
    |        +------------- Мнемоника
    |        |      +---------- Разрядность операции
    |        |      |       +------- Операнды
    |        |      |       |        (в порядке destination, source1, source2)
    |        |      |       |               +---------- Комментарии
    |        |      |       |               |
    V        V	V       V               V
    x86	ADD	8	RR		add	rd,rs		86
            8	RI{8S}		add	rd,imm          86
            16	RR	                                86
            16	RI{8S,16}                               86

Для операндов
    R - регистр
    I - непосредственное число (immediate)
    I{8S} - значит 8бит непосредственное число, которое sign-extent


35.2.1.1. АРИФМЕТИЧЕСКИЕ КОМАНДЫ

  Addition

Сложение

    destination = source1 + source2;

Операция складывает два своих операнда (source1 и source2) и
помещает результат в destination.

Поскольку данные представлены в дополнительном коде, то команда
обслуживает сразу и signed и unsigned числа.

Как правило непосредственные (immediate) (числовые) операнды
содержаться в команде как sign-extended числа.

CISC-based процессоры как правило имеют отдельные формы команд для
всех размеров операндов.

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

Как правило Addition модифицирует все основные арифметические флаги
(carry, zero, sign, overflow). Но существуют процессоры (например PowerPC),
которые имеют версии команд которые модифицируют флаги (add.), и которые
не модифицируют (add). А есть процессоры которые вообще не ставят флаги после
операций.

Некоторые процесоры (HPPA, ARM, IA64) могут выполнять данную команду по
определенным условиям.

Некоторые процессоры при определенных условиях могут вызывать Trap при
возникновении переполнения (при операциям с signed integer).
Для других процессоров отслеживание signed переполнения и вызов соответсвующего
Trap требуют дополнительных команд, например x86:

    add	ax,bx
    into         	; Trap if overflow flag set

Для отслеживания необязательно использовать Trap, можно использовать и
условных переход по флагу переполнения (если он конечно есть)

    add	eax,ebx
    jo	label	; Conditionalm Jump if Overflow

 --------------------------------------------------------------------------
o	Unsigned/Signed  Addition w/o Carry

    x86	ADD	8	RR		add	rd,rs		86
            8	RI{8S}		add	rd,imm          86
            16	RR	                                86
            16	RI{8S,16}                               86
            32	RR	                                386
            32	RI{8S,32}                               386
    ------------------------------------
    Alpha	ADDL	32	RRR		addl	ra,rb,rc        21064
                          rc = sext(ra[31..0] + rb[31..0])
            32	RRI{8S}                                 21064
                        addl    ra,#imm,rc
        ADDQ	64	RRR		addq	ra,rb,rc        21064
                          rc = ra + rb
            64	RRI{8S}		addq	ra,#imm,rc      21064
    ------------------------------------
    PPC	ADD	max	RRR		add	rD,rA,rB
                          rD = rA + rB
        ADD.	max	RRR		[set flags]
        ADDO	max	RRR		[check overflow]
        ADDO.	max	RRR	 	[set flags,set overflow]
        ADDI	max	RRI{16S}	addi	rD,rA,IMM
    ------------------------------------
    MIPS	ADD	32	RRR		add	rd,rs,rt   	MIPS I
                          rd = rs + rt
                          Trap if overflow
        ADDI	32	RRI{16S}	addi	rt,rs,imm       MIPS I
                          rt = rs + imm
                          Trap if overflow
        ADDIU	32	RRI{16S}	addiu	rt,rs,imm	MIPS I
                          rt = rs + imm
        ADDU	32	RRR		  addu	rd,rs,rt	MIPS I
                          rd = rs + rt
        DADD	64	RRR		dadd	rd,rs,rt	MIPS III
                          rd = rs + rt
                          Trap if overflow
        DADDI	64	RRI{16S}	daddi	rt,rs,imm	MIPS III
                          rt = rs + imm
                          Trap if overflow
        DADDIU	64	RRI{16S}	daddiu	rt,rs,imm 	MIPS III
                          rt = rs + imm
        DADDU	64	RRR		daddu	rd,rs,rt	MIPS III
                          rd = rs + rt
    ------------------------------------
    SPARC	ADD	max	RRR		add	rs1,rs2,rd	V8
            max	RRI{13S}	add	rs1,imm,rd	V8
        ADDcc	max	RRR		addcc	rs1,rs2,rd	V8
                        [Modify condition codes]
            max	RRI{13S}	addcc	rs1,imm,rd	V8
    ------------------------------------
    68K	ADD	8	RR		(D-regs)
            16	RR
            32	RR
        ADDA	16	RR		(A-regs)
            32	RR
        ADDI	8	RI		(A-,D- regs)
            16	RI		[ADDQ - nibble]
            32	RI
    ------------------------------------
    z80	ADD	8	AR	AI
            16	AR
    ------------------------------------
    HPPA	ADDc	32	RRR
        ADDLc	32	RRR		(Not Affect PSW C/B-bit)
        ADDIc	32	I11,RR
        ADDIL	32	I21,R
    ------------------------------------
    VAX-11	ADDB2	8	RR
        ADDB3	8	RRR
        ADDW2	16	RR
        ADDW3	16	RRR
        ADDL2	32	RR
        ADDL3	32	RRR
    ------------------------------------
    IA-64	ADD	64	R,R,R
        ADDS	64	R,R,I14
        ADDL	64	R,R,I22
    ------------------------------------
    MCS51	ADD	8	AR
            8	AM
            8	AI
    ------------------------------------
    JVM	IADD	32
        LADD	64
    ------------------------------------
    ARM	ADDcc	32	RRR	RRI
    ------------------------------------
    SH4	ADD		RR	RI
        ADDV		RR		(set overflow flag)

  Addition with Carry

Сложение с флагом переноса

    destination = source1 + source2 + CF;

Операция складывает два своих операнда и Carry Flag и помещает
результат в destination.

Эта команда черезвычайна важна для выполнения вычислений с арифметикой
большой точности.  (Смотри раздел 41.2)

Процессоры которые не поддерживают такую команду напрямую могут ее эмулировать
выполняя установку регистра в 0 или 1 в зависимости от условия, и последущего
сложения затем.

Но если нам нужна просто арифметика расширенной точности, то
Собсвенно подсказкой для работы в дополнительном коде, служит:
Carry flag устанавливается когда:
    result = X + Y  < X

         P + P  = P	no carry
         P + P  = N	no carry
         P + N  = N	no carry
         P + N  = P	carry
         N + P  = P	carry
         N + P  = N	no carry
         N + N  = N     carry
         N + N  = P     carry

Процессоры Alpha не поддерживают такую команду. Действие выполняемое командой
реализуется через следующую последовательность команд:
    cmovlt

TODO: Check this sequence - this sequence is wrong

    ! R1:R2 = R3:R4 + R5:R6

    addq	r4,r6,r2	! r2 = r4 + r6
    subq	r2,r4,r7	! r7 = r6
    and	r31,r31,r8	! r8 = 0
    cmovlt	r7,1,r8		! r8 = carry (r7 < 0)? 1: 0
    addq	r3,r5,r1	! add high part
    addq	r1,r8,r1	! add carry to high part

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

    ; R1:R2 = R3:R4 + R5:R6
    ; used R7
    add	r2,r4,r6
    sltu	r7,r2,r4
    add	r1,r3,r5
    add	r1,r1,r7

IA-64 поддерживает форму команды сложения

    add	r1=r2,r3,1

Поскольку IA-64 содержит предикаты выполнения то аналог сложения с Carry
будет пара команд
    (p1)	r1=r2,r3,1
    (p2)	r1=r2,r3
    ;;
при условии что предикаты выставлены ранее.

    // Addition:  R1:R2 = R3:R4 + R5:R6
    add	r2 = r4,r6
    ;;
    cmp.ltu	p1,p2 = r2,r4
    ;;
(p1)	add	r1 = r3,r5,1
(p2)	add	r1 = r2,r5

 ---------------------------------------------------------------------------
o	Unsigned/Signed Addition with Carry

    x86	ADC	8	RR	RI
            16	RR	RI
            32	RR	RI
    ------------------------------------
    Alpha	(*) CMOVxx +  ADDxx
    ------------------------------------
    PPC	ADDC	max	RRR
        ADDIC	max	RRR
    ------------------------------------
    MIPS	(*) ADDU/ADDIU Look !!!
    ------------------------------------
    SPARC	ADDX	max	RRR	RRI
    ------------------------------------
    68K	ADDX	8	RR		(D-regs)
            16	RR
            32	RR
    ------------------------------------
    z80	ADC	8	AR	AI
            16	AR
    ------------------------------------
    HPPA	ADDCc	32	RRR
    ------------------------------------
    VAX-11	ADWC	32	RR
    ------------------------------------
    IA-64	ADD	64	RRR1	(*) More complex
    ------------------------------------
    MCS51	ADDC	8	AR
                AM
                AI
    ------------------------------------
    ARM	ADCcc	32	RRR	RRI
    ------------------------------------
    SH4	ADDC		RR

  Addition Scale/Index/Base

    destination = source1 + source2 * scale

Команда используется для вычисления адрессов в массивах.
Scale - фиксированная константа (кратная степени 2 - как правило 2,4,8).

Преймущество команды в том что она быстрая, в отличии от пары сложение+сдвиг,
и тем более сложение+обычное_умножение.

На x86 команда использует мнемонику ориентированную на доступ к памяти, но
реально команда не обращается к памяти, а просто вычисляет адресс, который
и записывается в destination register.
Это пример разумного использования AGU для оптимизации вычислений.

    lea	eax,[ebx + ecx * 8 + 1234h]

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

 ---------------------------------------------------------------------------
o	Unsigned Addition Scale/Index/Base

    x86	LEA	32	RRR		scale = 2,4,8
    -------------------------------------
    Alpha	S4ADDL	32	RRR	RRI	scale = 4
        S8ADDL	32	RRR	RRI	scale = 8
        S4ADDQ	64	RRR	RRI	scale = 4
        S8ADDQ	64	RRR	RRI	scale = 8
    -------------------------------------
    PPC	(*) Complex Sequence
    -------------------------------------
    MIPS	(*) Complex Sequence
    -------------------------------------
    68K	(*) Complex sequence
    -------------------------------------
    z80	(*) Complex sequence
    -------------------------------------
    HPPA	SH1ADD	32	RRR		scale = 2
        SH1ADDL 32	RRR		scale = 2 (Not affect PSW C/B)
        SH2ADD	32	RRR		scale = 4
        SH2ADDL	32	RRR		scale = 4 (Not affect PSW C/B)
        SH3ADD	32	RRR		scale = 8
        SH3ADDL	32	RRR		scale = 8 (Not affect PSW C/B)

  Subtract

Вычитание

    destination = source1 - source2

Команда вычитает один свой операнд из другого и помещает результат в
destination.

Поскольку данные представлены в дополнительном коде, то команда
обслуживает сразу и signed и unsigned числа.

Читай замечания для Addition

PowerPC поддерживают интересную операцию subfic:

которая вычитает source операнд из нуля, что бывает часто полезно.

 ---------------------------------------------------------------------------
o	Unsigned/Signed General Integer Subtractions w/o Carry

    x86	SUB	8	RR	RI
            16	RR	RI
            32	RR	RI
    -------------------------------------
    Alpha	SUBL	32	RRR	RRI
        SUBQ	64	RRR	RRI
    -------------------------------------
    PPC	SUBF	max	RRR
        SUBFI	max	RRI
    -------------------------------------
    MIPS	SUB	32	RRR
        DSUB	64	RRR
    -------------------------------------
    SPARC	SUB	max	RRR	RRI
    -------------------------------------
    68K	SUB	8	RR		(D-regs)
            16	RR
            32	RR
        SUBA	8	RR		(A-regs)
            16	RR
            32	RR
        SUBI	8	RI		(A-,D- regs)
            16	RI		[SUBQ - nibble]
            32	RI
    --------------------------------------
    z80	SUB	8	AR	AI
    --------------------------------------
    HPPA	SUBc	32	RRR
        SUBIc	32	I11,RR
    --------------------------------------
    VAX-11	SUBB2	8	RR
        SUBB3	8	RRR
        SUBW2	16	RR
        SUBW3	16	RRR
        SUBL2	32	RR
        SUBL3	32	RRR
    --------------------------------------
    IA-64	SUB	max	R1=R2,R3
            max	R1=I8,R3
            max	R1=R2,R3,1
    ---------------------------------------
    MCS51	(*)	Complex
    ---------------------------------------
    JVM	ISUB	32
        LSUB	64
    ---------------------------------------
    ARM	SUBcc	32	RRR     RRI
        RSBcc	32	RRR     RRI
    ---------------------------------------
    SH4	SUB		RR
        SUBV		RR		(set overflow)

  Subtract with Borrow

Вычитание с заемом

    destination = source1 - source2 - CF

Команда вычитает один свой операнд из другого, вычитает еще Carry Flag и помещает
результат в destination.

Эта команда черезвычайна важна для выполнения вычислений с арифметикой
большой точности.  (Смотри раздел 41.2)

Процессоры Alpha не поддерживают такую команду. Действие выполняемое командой
реализуется через следующую последовательность команд:
    cmov	ult форма
    subq

Аналогично MIPS.

Смотри также комментарии к Addition.

--------------------------------------------------------------------
o	Unsigned/Signed General Integer Subtraction with Borrow

    x86	SBC	8	RR	RI
            16	RR	RI
            32	RR	RI
    -------------------------------------
    Alpha	(*) CMOVxx + SUBLxx
    -------------------------------------
    PPC	SUBFC	max	RRR
        SUBFIC	max	RRI
    --------------------------------------
    MIPS	(*) SUBU/DSUBU ???
    --------------------------------------
    SPARC	SUBX	max	RRR	RRI
    --------------------------------------
    68K	SUBX	8	RR		(D-regs)
            16	RR
            32	RR
    --------------------------------------
    z80	SBC	8	AR	AI
            16	AR
    --------------------------------------
    HPPA	SUBBc	32	RRR
    --------------------------------------
    MCS51	SUBB	8	AR
                AM
                AI
    --------------------------------------
    ARM	SBCcc	32	RRR	RRI
        RSCcc	32	RRR	RRI
    --------------------------------------
    SH4	SUBC		RR

  Subtract Scale/Index/Base

    destination = source1 - source2 * scale

Команда используется для вычисления адрессов в массивах.
Scale - фиксированная константа (кратная степени 2 - как правило 2,4,8).

Преймущество команды в том что она быстрая, в отличии от пары сложение+сдвиг,
и тем более сложение+обычное_умножение.

 -----------------------------------------------------------------------------
o 	Unsigned subtraction Scale/Index/Base

    x86	(*) Complex sequence
    ---------------------------------------
    Alpha	S4SUBL	32	RRR	RRI	(scale = 4)
        S8SUBL	32	RRR	RRI	(scale = 8)
        S4SUBQ	64	RRR	RRI	(scale = 4)
        S8SUBQ	64	RRR	RRI	(scale = 8)
    ----------------------------------------
    PPC	(*) Complex sequence
    ----------------------------------------
    MIPS	(*) Complex sequence
    ----------------------------------------
    68K	(*) Complex sequence
    ----------------------------------------
    z80	(*) Complex sequence
    ----------------------------------------
    HPPA	(*) see Unsigned addition Scale/Index/Base

  Unsigned Multiply

    destination = source1 (unsigned *) source2

Команда выполняет умножение операндов.

Возможные формы команды:

MULU 	Multiply Unsigned   		XX * XX -> XXXX

Беззнаково умножает два операнда и помещает результат в destination,
который имеет размер в 2 раза больше чем каждый из операндов.

MULL	Multiply Low (Signed/Unsigned)  XX * XX -> LOW(XXXX) = XX

Для дополнительного кода младшая половина результата умножения, который
имеет размер равный удвоенному размеру каждого из операндов - одинакова
и для знакового и для беззнакового умножения.

MULHU	Multiply High Unsigned		XX * XX -> HIGH(XXXX) = XX

Беззнаково умножает операнды и возвращает старшую часть результата.

Как правило процессоры имеют либо инструкцию типа MULU (результат часто
может записываться только в определенные регистры (пример:
x86: EDX:EAX, MIPS: HI:LO)),
либо набор MULL и пару MULH - одну для знакового, другое для беззнакового
умножения.

При полном умножении MULU или при MULHU переполнение не может возникнуть, поэтому OF=0

 ------------------------------------------------------------------------------
o	Unsigned Integer Multiply

    x86	MUL	8	AccR			( 8x8  -> 16)
            16	AccR			(16x16 -> 32)
            32	AccR			(32x32 -> 64)
    ----------------------------------------
    Alpha	UMULH	64	RRR	RRI		(64x64 -> 128 (high))
        MULQ	64	RRR	RRI		(64x64 -> 128 (low)))
    ----------------------------------------
    PPC	MULHWU	32	RRR			(32x32 -> 64  (high))
        MULL	32	RRR			(32x32 -> 64  (low))
        MULHDU	64	RRR			(64x64 -> 128 (high))
        MULLD	64	RRR			(64x64 -> 128 (low))
    ----------------------------------------
    MIPS	MULTU	32	AccR			(32x32 -> 64)  (HI,LO)
        DMULTU	64	AccR			(64x64 -> 128) (HI,LO)
    ----------------------------------------
    SPARC	UMUL	32	RRR	RRI
        MULX	64	RRR		 V9	(Generic 64bit Mul)
    ----------------------------------------
    68K	MULU	16	RR	  (D-regs)	(16x16 -> 32)
            32	RR			(32x32 -> 32) ??
    ----------------------------------------
    z80	(*) Complex sequence
    ----------------------------------------
    HPPA	???
    ----------------------------------------
    VAX-11	???
        MULB2	8	RR
        MULB3	8	RRR
        MULW2	16	RR
        MULW3	16	RRR
        MULL2	32	RR
        MULL3	32	RRR
    -----------------------------------------
    MCS51	MUL	8	AB			(BA <- A x B)
    -----------------------------------------
    ARM	UMULLcc	32	RRRR			(32:32 <- 32 * 32)
    -----------------------------------------
    SH4	MULU.W		RR			(16x16 -> 32)
        DMULU.L		RR			(32x32 -> 64)

HP-PA Multiply:

#ifdef L_multiply
#define	op0	%r26
#define	op1	%r25
#define res	%r29
#define ret	%r31
#define tmp	%r1

SPACE
GSYM($$mulU)
GSYM($$mulI)
    .proc
    .callinfo	frame=0,no_calls
    .entry
    addi,tr		0,%r0,res	; clear out res, skip next insn
LSYM(loop)
    zdep		op1,26,27,op1	; shift up op1 by 5
LSYM(lo)
    zdep		op0,30,5,tmp	; extract next 5 bits and shift up
    blr		tmp,%r0
    extru		op0,26,27,op0	; shift down op0 by 5
LSYM(0)
    comib,<>	0,op0,LREF(lo)
    zdep		op1,26,27,op1	; shift up op1 by 5
    bv		%r0(ret)
    nop
LSYM(1)
    b		LREF(loop)
    addl		op1,res,res
    nop
    nop
LSYM(2)
    b		LREF(loop)
    sh1addl		op1,res,res
    nop
    nop
LSYM(3)
    sh1addl		op1,op1,tmp	; 3x
    b		LREF(loop)
    addl		tmp,res,res
    nop
LSYM(4)
    b		LREF(loop)
    sh2addl		op1,res,res
    nop
    nop
LSYM(5)
    sh2addl		op1,op1,tmp	; 5x
    b		LREF(loop)
    addl		tmp,res,res
    nop
LSYM(6)
    sh1addl		op1,op1,tmp	; 3x
    b		LREF(loop)
    sh1addl		tmp,res,res
    nop
LSYM(7)
    zdep		op1,28,29,tmp	; 8x
    sub		tmp,op1,tmp	; 7x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(8)
    b		LREF(loop)
    sh3addl		op1,res,res
    nop
    nop
LSYM(9)
    sh3addl		op1,op1,tmp	; 9x
    b		LREF(loop)
    addl		tmp,res,res
    nop
LSYM(10)
    sh2addl		op1,op1,tmp	; 5x
    b		LREF(loop)
    sh1addl		tmp,res,res
    nop
LSYM(11)
    sh2addl		op1,op1,tmp	; 5x
    sh1addl		tmp,op1,tmp	; 11x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(12)
    sh1addl		op1,op1,tmp	; 3x
    b		LREF(loop)
    sh2addl		tmp,res,res
    nop
LSYM(13)
    sh1addl		op1,op1,tmp	; 3x
    sh2addl		tmp,op1,tmp	; 13x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(14)
    zdep		op1,28,29,tmp	; 8x
    sub		tmp,op1,tmp	; 7x
    b		LREF(loop)
    sh1addl		tmp,res,res
LSYM(15)
    zdep		op1,27,28,tmp	; 16x
    sub		tmp,op1,tmp	; 15x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(16)
    zdep		op1,27,28,tmp	; 16x
    b		LREF(loop)
    addl		tmp,res,res
    nop
LSYM(17)
    zdep		op1,27,28,tmp	; 16x
    addl		tmp,op1,tmp	; 17x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(18)
    sh3addl		op1,op1,tmp	; 9x
    b		LREF(loop)
    sh1addl		tmp,res,res
    nop
LSYM(19)
    sh3addl		op1,op1,tmp	; 9x
    sh1addl		tmp,op1,tmp	; 19x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(20)
    sh2addl		op1,op1,tmp	; 5x
    b		LREF(loop)
    sh2addl		tmp,res,res
    nop
LSYM(21)
    sh2addl		op1,op1,tmp	; 5x
    sh2addl		tmp,op1,tmp	; 21x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(22)
    sh2addl		op1,op1,tmp	; 5x
    sh1addl		tmp,op1,tmp	; 11x
    b		LREF(loop)
    sh1addl		tmp,res,res
LSYM(23)
    sh1addl		op1,op1,tmp	; 3x
    sh3addl		tmp,res,res	; += 8x3
    b		LREF(loop)
    sub		res,op1,res	; -= x
LSYM(24)
    sh1addl		op1,op1,tmp	; 3x
    b		LREF(loop)
    sh3addl		tmp,res,res	; += 8x3
    nop
LSYM(25)
    sh2addl		op1,op1,tmp	; 5x
    sh2addl		tmp,tmp,tmp	; 25x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(26)
    sh1addl		op1,op1,tmp	; 3x
    sh2addl		tmp,op1,tmp	; 13x
    b		LREF(loop)
    sh1addl		tmp,res,res	; += 2x13
LSYM(27)
    sh1addl		op1,op1,tmp	; 3x
    sh3addl		tmp,tmp,tmp	; 27x
    b		LREF(loop)
    addl		tmp,res,res
LSYM(28)
    zdep		op1,28,29,tmp	; 8x
    sub		tmp,op1,tmp	; 7x
    b		LREF(loop)
    sh2addl		tmp,res,res	; += 4x7
LSYM(29)
    sh1addl		op1,op1,tmp	; 3x
    sub		res,tmp,res	; -= 3x
    b		LREF(foo)
    zdep		op1,26,27,tmp	; 32x
LSYM(30)
    zdep		op1,27,28,tmp	; 16x
    sub		tmp,op1,tmp	; 15x
    b		LREF(loop)
    sh1addl		tmp,res,res	; += 2x15
LSYM(31)
    zdep		op1,26,27,tmp	; 32x
    sub		tmp,op1,tmp	; 31x
LSYM(foo)
    b		LREF(loop)
    addl		tmp,res,res
    .exit
    .procend
#endif

  Signed Multiply

    destination = source1 (signed *) source2

Возможные формы:

MULS	Multiply Signed			XX * XX -> XXXX

Знаково умножает два операнда и помещает результат в destination,
который имеет размер в 2 раза больше чем каждый из операндов.

MULHS	Multiply High Unsigned		XX * XX -> HIGH(XXXX) = XX

Беззнаково умножает операнды и возвращает старшую часть результата.

смотри замечания к предидущей команде.

При полном умножении (MULS) или при MULHS переполнение не может возникнуть, поэтому OF=0

 -------------------------------------------------------------------------------
o	Signed Integer Multiply

    x86	IMUL	8	AccR			( 8x8  -> 16)
            8	RR	RI		( 8x8  -> 8)
            8	RRR	RRI		( 8x8  -> 8)
            16	AccR			(16x16 -> 32)
            16	RR	RI		(16x16 -> 16)
            16	RRR	RRI		(16x16 -> 16)
            32	AccR			(32x32 -> 64)
            32	RR	RI		(32x32 -> 32)
            32	RRR	RRI		(32x32 -> 32)
    ------------------------------------------
    Alpha	MULL	32	RRR	RRI		(32x32 -> 64)
        MULQ	64	RRR	RRI		(64x64 -> 128)
    ------------------------------------------
    PPC	MULLHW	32	RRR			(32x32 -> 64)  (high)
        MULL	32	RRR			(32x32 -> 64)  (low)
        MULLHD	64	RRR			(64x64 -> 128) (high)
        MULLD	64	RRR			(64x64 -> 128) (low)
    ------------------------------------------
    MIPS	MULT	32	AccR			(32x32 -> 64)  (HI,LO)
        DMULT	64	AccR			(64x64 -> 128) (HI,LO)
    ------------------------------------------
    SPARC	SMUL	32	RRR	RRI
    ------------------------------------------
    68K	MULS	16	RR	(D-regs)	(16x16 -> 32)
            32	RR			(32x32 -> 32) ??
    ----------------------------------------
    z80	(*) Complex sequence
    ----------------------------------------
    HPPA	???
    ----------------------------------------
    VAX-11	???
    ----------------------------------------
    JVM	IMUL	32
        LMUL	64
    ----------------------------------------
    ARM	MULcc	32	RRR			(32x32 -> 32)
        SMULLcc 32	RRRR			(32x32 -> 32:32)
    -----------------------------------------
    SH4	MULS.W		RR			(16x16 -> 32)
        DMULS.L		RR			(32x32 -> 64)

  Unsigned Division

Беззнаковое деление (и остаток)

    destination = source1 (unsigned /) source2

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

А бывает divide дает только частное

а остаток от деления реализуется другой командой
(или вообще нету команды для остатка).

Практически все используют форму XXXX / XX -> XX
Часто делимое должно быть помещено в специальные регистры
(x86: EDX:EAX, MIPS: HI:LO)

Часто при делении вместе с частным вычисляется и остаток.
То есть и частное и остаток получается в результате выполнения одной команды.

Не у всех процессоров есть деление - например у Alpha его нет.

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

При переполнении после деления:
    - Деление на 0
    - Результат не уместился в регистр
может возникать Trap Division by zero.

PPC Remainder вычисляеться как:

    # 64-bit signed
        divd	RT,RA,RB	# RT = quotient
        mulld	RT,RT,RB	# RT = quotient * divisor
        subf	RT,RT,RA	# RT = remainder

 ------------------------------------------------------------------------------
o	Unsigned Integer Division

    x86	DIV	8	AccR			(16/8  -> 8)
            16	AccR			(32/16 -> 16)
            32	AccR			(64/32 -> 32)
    -------------------------------------------
    Alpha	(*) Complex code - not core implemented
    -------------------------------------------
    PPC	DIVWU	32	RRR			(32/32 -> 32)
        DIVDU	64	RRR			(64/64 -> 64)
    -------------------------------------------
    MIPS	DIVU	32	AccR			(HI,LO)
        DDIVU	64	AccR			(HI,LO)
    -------------------------------------------
    SPARC	UDIV	32	RRR	RRI
        UDIVX	64	RRR	RRI		V9
    -------------------------------------------
    68K	DIVU	16	RR	(D-regs)	(32/16 -> 16)
        DIVUL	32	RR			(64/32 -> 32)
    -------------------------------------------
    z80	(*) Complex sequence
    -------------------------------------------
    HPPA	DSc	32	RRR			(Divide Step!!)
        (*) Divide is more complex
    -------------------------------------------
    VAX-11	DIVB2	8	RR
        DIVB3	8	RRR
        DIVW2	16	RR
        DIVW3	16	RRR
        DIVL2	32	RR
        DIVL3	32	RRR
    --------------------------------------------
    MCS51	DIV	8	AB			(A,B <- A/B)
    --------------------------------------------
    SH4	(*) complex sequence
        of DIV1/DIV0U

HP-PA Divide

#ifdef L_divU
#define dividend %r26
#define divisor %r25
#define tmp %r1
#define quotient %r29
#define ret %r31

SPACE
GSYM($$divU)
    .proc
    .callinfo	frame=0,no_calls
    .entry
    comb,<		divisor,0,LREF(largedivisor)
        sub		%r0,divisor,%r1		; clear cy as side-effect
    ds		%r0,%r1,%r0
    addc		dividend,dividend,dividend
    ds		%r0,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,dividend
    ds		%r1,divisor,%r1
    addc		dividend,dividend,quotient
    ds		%r1,divisor,%r1
    bv		%r0(ret)
    addc		quotient,quotient,quotient
LSYM(largedivisor)
    comclr,<<	dividend,divisor,quotient
    ldi		1,quotient
    bv,n		%r0(ret)
    .exit
    .procend
#endif

// IA-64 Unsigned Divide

__udivdi3:

{ .mii
  alloc r31=ar.pfs,2,0,0,0
  nop.i 0
  nop.i 0;;
}
{ .mmi
  setf.sig f8=r32
  setf.sig f9=r33
  nop.i 0;;
}
{ .mfb
  nop.m 0
  fma.s1 f6=f8,f1,f0
  nop.b 0
}
{ .mfb
  nop.m 0
  fma.s1 f7=f9,f1,f0
  nop.b 0;;
}
{ .mfi
  nop.m 0
  // Step (1)
  // y0 = 1 / b in f8
  frcpa.s1 f8,p6=f6,f7
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (2)
  // e0 = 1 - b * y0 in f9
  (p6) fnma.s1 f9=f7,f8,f1
  nop.i 0
}
{ .mfi
  nop.m 0
  // Step (3)
  // q0 = a * y0 in f10
  (p6) fma.s1 f10=f6,f8,f0
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (4)
  // e1 = e0 * e0 in f11
  (p6) fma.s1 f11=f9,f9,f0
  nop.i 0
}
{ .mfi
  nop.m 0
  // Step (5)
  // q1 = q0 + e0 * q0 in f10
  (p6) fma.s1 f10=f9,f10,f10
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (6)
  // y1 = y0 + e0 * y0 in f8
  (p6) fma.s1 f8=f9,f8,f8
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (7)
  // q2 = q1 + e1 * q1 in f9
  (p6) fma.s1 f9=f11,f10,f10
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (8)
  // y2 = y1 + e1 * y1 in f8
  (p6) fma.s1 f8=f11,f8,f8
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (9)
  // r2 = a - b * q2 in f10
  (p6) fnma.s1 f10=f7,f9,f6
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (10)
  // q3 = q2 + r2 * y2 in f8
  (p6) fma.s1 f8=f10,f8,f9
  nop.i 0;;
}
{ .mfb
  nop.m 0
  // (11) q = trunc(q3)
  fcvt.fxu.trunc.s1 f8=f8
  nop.b 0;;
}
{ .mmi
  // quotient will be in r8 (if b != 0)
  getf.sig r8=f8
  nop.m 0
  nop.i 0;;
}
{ .mmb
  nop.m 0
  nop.m 0
  br.ret.sptk b0;;
}

  Signed Divison

Деление знаковое (и остаток)

    destination = source1 (signed /) source2

смотри замечания к Unigned Division

 ------------------------------------------------------------------------------
o	Signed Integer Division

    x86	IDIV	8	AccR			(16/8  -> 8)
            16	AccR			(32/16 -> 16)
            32	AccR			(64/32 -> 32)
    -------------------------------------------
    Alpha	(*) Complex code - not core implemented
    -------------------------------------------
    PPC	DIVW	32	RRR			(32/32 -> 32)
        DIVD	64	RRR			(64/64 -> 64)
    -------------------------------------------
    MIPS	DIV	32	AccR			(HI,LO)
        DDIV	64	AccR			(HI,LO)
    -------------------------------------------
    SPARC	SDIV	32	RRR	RRI
        SDIVX	64	RRR	RRI		V9
    -------------------------------------------
    68K	DIVS	16	RR	(D-regs)	(32/16 -> 16) ??
        DIVSL	32	RR			(64/32 -> 32)
    -------------------------------------------
    z80	(*) Complex sequence
    -------------------------------------------
    HPPA	(*) Complex sequence
    -------------------------------------------
    VAX-11	???
    -------------------------------------------
    JVM	IDIV	32
        IREM	32				(Remainder)
        LDIV	64
        LREM	64				(Remainder)
    --------------------------------------------
    SH4	(*) complex sequence
        of DIV1/DIV0S

// IA-64 Signed Division

__divdi3:

{ .mii
  alloc r31=ar.pfs,2,0,0,0
  nop.i 0
  nop.i 0;;
}

{ .mmi
  setf.sig f8=r32
  setf.sig f9=r33
  nop.i 0;;
}
{ .mfb
  nop.m 0
  fcvt.xf f6=f8
  nop.b 0
}
{ .mfb
  nop.m 0
  fcvt.xf f7=f9
  nop.b 0;;
}
{ .mfi
  nop.m 0
  // Step (1)
  // y0 = 1 / b in f8
  frcpa.s1 f8,p6=f6,f7
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (2)
  // e0 = 1 - b * y0 in f9
  (p6) fnma.s1 f9=f7,f8,f1
  nop.i 0
}
{ .mfi
  nop.m 0
  // Step (3)
  // q0 = a * y0 in f10
  (p6) fma.s1 f10=f6,f8,f0
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (4)
  // e1 = e0 * e0 in f11
  (p6) fma.s1 f11=f9,f9,f0
  nop.i 0
}
{ .mfi
  nop.m 0
  // Step (5)
  // q1 = q0 + e0 * q0 in f10
  (p6) fma.s1 f10=f9,f10,f10
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (6)
  // y1 = y0 + e0 * y0 in f8
  (p6) fma.s1 f8=f9,f8,f8
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (7)
  // q2 = q1 + e1 * q1 in f9
  (p6) fma.s1 f9=f11,f10,f10
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (8)
  // y2 = y1 + e1 * y1 in f8
  (p6) fma.s1 f8=f11,f8,f8
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (9)
  // r2 = a - b * q2 in f10
  (p6) fnma.s1 f10=f7,f9,f6
  nop.i 0;;
}
{ .mfi
  nop.m 0
  // Step (10)
  // q3 = q2 + r2 * y2 in f8
  (p6) fma.s1 f8=f10,f8,f9
  nop.i 0;;
}
{ .mfb
  nop.m 0
  // Step (11)
  // q = trunc (q3)
  fcvt.fx.trunc.s1 f8=f8
  nop.b 0;;
}
{ .mmi
  // quotient will be in r8 (if b != 0)
  getf.sig r8=f8
  nop.m 0
  nop.i 0;;
}
{ .mmb
  nop.m 0
  nop.m 0
  br.ret.sptk b0;;
}

  Increment by 1

    destination = destination + 1

Часто используемая последовательность - например в циклах.
В CISC процессорах реализуется как одна команда
(Может модифицировать не все арифметические флаги)

В RISC процессорах как:
    add	destination, destination, immediate(1)

Например SPARC:

    inc	%r5	=>	add	%r5,1,%r5
    inccc	%r5	=>	addcc	%r5,1,%r5

 ------------------------------------------------------------------------------
o	Increment by 1

    x86	INC	8	R
            16	R
            32	R
    --------------------------------------------
    Alpha	(*)	ADDL/ADDQ	32/64	RRI	with 1
    --------------------------------------------
    PPC	(*)	ADDI		32/64	RRI	with 1
    --------------------------------------------
    MIPS	(*)	ADDI/DADDI	32/64	RRI	with 1
    --------------------------------------------
    68K	(*)	ADD/ADDA	8/16/32 RI	with 1
    --------------------------------------------
    SPARC	(*)	ADD		max	RRI	with 1
    --------------------------------------------
    z80	INC	8	R
            16	R
    --------------------------------------------
    HPPA	(*)	ADDIc		32	RR,I5	with 1
    --------------------------------------------
    VAX-11	INCB	8	R
        INCW	16	R
        INCL	32	R
    --------------------------------------------
    MCS51	INC	8	A
                R
                DPTR		(memory pointer register)
                M
    --------------------------------------------
    SH4	(*)	ADD	RI

  Decrement by 1

    destination = destination - 1

Часто используемая последовательность - например в циклах.
В CISC процессорах реализуется как одна команда
(Может модифицировать не все арифметические флаги)

В RISC процессорах как:
    sub	destination, destination, immediate(1)

Например SPARC:

    dec	%r5	=>	sub	%r5,1,%r5
    deccc	%r5	=>	subcc	%r5,1,%r5

 ----------------------------------------------------------------------------
o	Decrement by 1

    x86	DEC	8	R
            16	R
            32	R
    --------------------------------------------
    Alpha	(*)	SUBL/SUBQ	32/64	RRI	with 1
    --------------------------------------------
    PPC	(*)	SUBF		32/64	RRI	with 1
    --------------------------------------------
    MIPS	(*)	ADDI/DADDI	32/64	RRI	with 1
    --------------------------------------------
    SPARC	(*)	SUB		max	RRI	with 1
    --------------------------------------------
    68K	(*)	ADD/ADDA	8/16/32 RI	with 1
    --------------------------------------------
    z80	DEC	8	R
            16	R
    --------------------------------------------
    HPPA	(*)	SUBIc		32	RR,I5	with 1
    --------------------------------------------
    VAX-11	DECB	8	R
        DECW	16	R
        DECL	32	R
    --------------------------------------------
    MCS51	DEC	8	A
                R
                M
                DPTR		(memory pointer register)
    --------------------------------------------
    SH4	(*)	complex sequence

  Negate

    destination = - source

В CISC процессорах реализуется как отдельная команда
В RISC процессорах как последовательность

    sub	destination, R0, source

(R0 - регистр, который всегда содержит в себе 0)

Например SPARC:

    neg	%r5	  =>	sub	%g0,%r5,%r5
    neg	%r5,%r6	  =>	sub	%g0,%r5,%r6

 ----------------------------------------------------------------------------
o	Negate

    x86	DEC	8	R
            16	R
            32	R
    --------------------------------------------
    Alpha	(*)	SUBL/SUBQ	32/64	RRI	0 - value
    --------------------------------------------
    PPC	(*)	SUBF		32/64	RRI	0 - value
        (!!) 601: NEG instruction
    --------------------------------------------
    MIPS	(*)	ADDI/DADDI	32/64	RRI	0 - value
    --------------------------------------------
    SPARC	(*)	SUB		max	RRR	%g register
    --------------------------------------------
    68K	NEG	8	R		(A-,D- regs)
            16	R
            32	R
    --------------------------------------------
    z80	NEG	8	A
    ---------------------------------------------
    HPPA	???
    ---------------------------------------------
    VAX-11	MNEGB	8	RR			(R = -R)
        MNEGW	16	RR
        MNEGL	32	RR
    ----------------------------------------------
    JVM	INEG	32
        LNEG	64
    ----------------------------------------------
    ARM	(*)	Complex RSB from zero immediate
    ----------------------------------------------
    SH4	NEG		RR
 -----------------------------------------------------------------------------


35.2.1.2. ЛОГИЧЕСКИЕ КОММАНДЫ

Всего как мы помним есть
    4 однооперандных
и	16 двухоперандных логических функций
некоторые из которых вырождены.

Но основной набор, который поддерживают все
включает:
    AND,OR,XOR

Остальные могут не реализовываться

CISC процессоры как правило еще обязательно
имеют NOT.

                        Alpha	MIPS	HPPA	PPC	SPARC	IA-64
Register with value 0		r31	r0	r0	r0	r0

  Bitwize AND

Побитовый AND

    destination  = source1 AND source2

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	0
    0	1	|	0
    1	0	|	0
    1	1	|	1
    ------------------------------

 -----------------------------------------------------------------------------
o	Bitwize Logical AND

    x86	AND	8	RR	RI
            16	RR	RI
            32	RR	RI
    ---------------------------------------------
    Alpha	AND	32/64	RRR
    ---------------------------------------------
    PPC	AND	max	RRR
        ANDI.	max	RRI			(low)
        ANDIS.	max	RRI			(high)
    ---------------------------------------------
    MIPS	AND	32/64	RRR
        ANDI	32/64	RRR
    ---------------------------------------------
    SPARC	AND	max	RRR	RRI
    ---------------------------------------------
    68K	AND	8	RR			(D-regs)
            16	RR
            32	RR
        ANDI	8	RI			(D-,A- regs)
            16	RI
            32	RI
    ---------------------------------------------
    z80	AND	8	AR	AI
    ---------------------------------------------
    HPPA	ANDcc	32	RRR
    ---------------------------------------------
    VAX-11	(*) via XORs/MCOMs
    ---------------------------------------------
    IA-64	AND	64	R,R,R
                R,R,I8
    ---------------------------------------------
    MCS51	ANL	8	A,R
                A,M
                A,I
    ---------------------------------------------
    JVM	IAND	32
        LAND	64
    ---------------------------------------------
    ARM	ANDcc	32	RRR
                RRI
    ---------------------------------------------
    SH4	AND		RR

  Bitwize NOT

    destination = NOT source

    ----------------------
    source	| destination
    --------+-------------
    0	|	1
    1	|	0
    ----------------------

В CISC процессорах реализуется как отдельная команда
В RISC процессорах как последовательность

если RISC процессор поддерживает NAND или NOR

    nand	destination, source, source
    nand	destination, source, immediate(-1)
    nor	destination, source, R0
    nor	destination, source, immediate(0)

или как XOR c непосредственным операндом равным -1

    xor	destination, source, -1

Например SPARC:

    not	%r5,%r6	  =>	xnor	%r5,%g0,%r6
    not	%r5	  =>	xnor	%r5,%g0,%r6

 -----------------------------------------------------------------------------
o	Bitwize NOT

    x86	NOT	8	R
            16	R
            32	R
    ----------------------------------------------
    Alpha	(*) ORNOT with R31 (zero)
    ----------------------------------------------
    PPC	(*) XORI/XORIS	with FF...FF
    ----------------------------------------------
    MIPS	(*) XORI with FF....FF
    ----------------------------------------------
    SPARC	(*) XNOR	RRR			%g0 register
    ----------------------------------------------
    68K	NOT	8	R			(D-,A- regs)
            16	R
            32	R
    -----------------------------------------------
    z80	CPL	8	A
    -----------------------------------------------
    HPPA	(*) XORc	RRR			with r0
    -----------------------------------------------
    VAX-11	MCOMB	8	RR			(R <= ~ R)
        MCOMW	16	RR
        MCOML	32	RR
    -----------------------------------------------
    MCS51	CPL	8	A			(A = ~ A)
    ------------------------------------------------
    JVM	(*) Complex via XOR
    ------------------------------------------------
    ARM	(*) Complex via EOR
    ------------------------------------------------
    SH4	NOT		RR

  Bitwize OR

    destination  = source1 OR source2

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	0
    0	1	|	1
    1	0	|	1
    1	1	|	1
    ------------------------------

 -----------------------------------------------------------------------------
o	Bitwize Logical OR

    x86	OR	8	RR	RI
            16	RR	RI
            32	RR	RI
    ---------------------------------------------
    Alpha	BIS	32/64	RRR
    ---------------------------------------------
    PPC	OR	max	RRR
        ORI	max	RRI			(low)
        ORIS	max	RRI			(high)
    ---------------------------------------------
    MIPS	OR	32/64	RRR
        ORI	32/64	RRR
    ---------------------------------------------
    SPARC	OR	max	RRR	RRI
    ---------------------------------------------
    68K	OR	8	RR			(D-regs)
            16	RR
            32	RR
        ORI	8	RI			(D-,A-regs)
            16	RI
            32	RI
    ---------------------------------------------
    z80	OR	8	AR	AI
    ---------------------------------------------
    HPPA	ORc	32	RRR
    ---------------------------------------------
    VAX-11	(*) via XORs/MCOMs
    ---------------------------------------------
    IA-64	OR	64	R1=R2,R3
                R1=I8,R3
    ---------------------------------------------
    MCS51	ORL	8	A,R
                A,M
                A,I
    ---------------------------------------------
    JVM	IOR	32
        LOR	64
    ---------------------------------------------
    ARM	ORRcc	32	RRR
                RRI
    ---------------------------------------------
    SH4	OR		RR

  Bitwize XOR

    destination  = source1 XOR source2

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	0
    0	1	|	1
    1	0	|	1
    1	1	|	0
    ------------------------------

 --------------------------------------------------------------------------
o	Bitwize Logical XOR

    x86	XOR	8	RR	RI
            16	RR	RI
            32	RR	RI
    ---------------------------------------------
    Alpha	XOR	32/64	RRR
    ---------------------------------------------
    PPC	XOR	max	RRR
        XORI	max	RRI			(low)
        XORIS	max	RRI			(high)
    ---------------------------------------------
    MIPS	XOR	32/64	RRR
        XORI	32/64	RRR
    ---------------------------------------------
    SPARC	XOR	max	RRR	RRI
    ---------------------------------------------
    68K	EOR	8	RR			(D-regs)
            16	RR
            32	RR
        EORI	8	RI			(A-,D- regs)
            16	RI
            32	RI
    ---------------------------------------------
    z80	XOR	8	AR	AI
    ---------------------------------------------
    HPPA	XORc	32	RRR			(Generate Logical cond)
        UXORc	32	RRR			(Generate Unit cond.)
    ---------------------------------------------
    VAX-11	XORB2	8	RR
        XORB3	8	RRR
        XORW2	16	RR
        XORW3	16	RRR
        XORL2	32	RR
        XORL3	32	RRR
    ---------------------------------------------
    IA-64	XOR	64	R1=R2,R3
                R1=I8,R3
    ---------------------------------------------
    MCS51	XRL	8	A,R
                A,M
                A,I
    ----------------------------------------------
    JVM	IXOR	32
        LXOR	64
    ----------------------------------------------
    ARM	EORcc	32	RRR
                RRI
    ----------------------------------------------
    SH4	XOR		RR

  Logical NOR

    destination = source1 NOR source2

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	0
    0	1	|	0
    1	0	|	0
    1	1	|	1
    ------------------------------

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

    NOR(x,y) = NOT(OR(x,y))

 -----------------------------------------------------------------------------
o	Bitwize Logical OR-NOT

    x86	(*) Complex sequence
    -----------------------------------------------
    Alpha	ORNOT	32/64	RRR
    -----------------------------------------------
    PPC	NOR	max	RRR
    -----------------------------------------------
    MIPS	NOR	32/64	RRR
    -----------------------------------------------
    SPARC	ORN	max	RRR	RRI
    -----------------------------------------------
    68K	(*) Complex sequence
    -----------------------------------------------
    z80	(*) Complex sequence
    ---------------------------------------------
    VAX-11	(*) via XORs/MCOMs

  Logical Equivalence

    destination = source1 EQV source2

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	1
    0	1	|	0
    1	0	|	0
    1	1	|	1
    ------------------------------

 ------------------------------------------------------------------------------
o	Bitwize Equvalence

    x86	(*) Complex sequence
    -----------------------------------------------
    Alpha	EQV	32/64	RRR
    -----------------------------------------------
    PPC	EQV	max	RRR
        EQV.	max	RRR
    -----------------------------------------------
    MIPS	(*) Complex sequence
    -----------------------------------------------
    SPARC	(*) Complex sequence
    -----------------------------------------------
    68K	(*) Complex sequence
    -----------------------------------------------
    z80	(*) Complex sequence
    -----------------------------------------------
    HPPA	(*) Complex sequence
    ---------------------------------------------
    VAX-11	(*) via XORs/MCOMs

  Logical NAND

    destination = source1 NAND source2

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	1
    0	1	|	1
    1	0	|	1
    1	1	|	0
    ------------------------------

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

    NAND(x,y) = NOT(AND(x,y))

 ------------------------------------------------------------------------------
o	Bitwize AND-NOT

    x86	(*) Complex sequence
    -----------------------------------------------
    Alpha	BIC	32/64	RRR
    -----------------------------------------------
    PPC	NAND	max	RRR
    -----------------------------------------------
    MIPS	(*) Complex sequence
    -----------------------------------------------
    SPARC	ANDN	max	RRR	RRI
    -----------------------------------------------
    68K	(*) Complex sequence
    -----------------------------------------------
    z80	(*) Complex sequence
    -----------------------------------------------
    HPPA	ANDCMc	32	RRR
    -----------------------------------------------
    IA-64	ANDCM	64	R,R,R
                R,I8,R
    -----------------------------------------------
    ARM	BICcc	32	RRR	RRI

  Bitwize XNOR

    destination = source1 XNOR source2

Экивалентность

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	1
    0	1	|	0
    1	0	|	0
    1	1	|	1
    ------------------------------

 ------------------------------------------------------------------------------
o	Bitwize logical XNOR

    x86	(*) Complex sequence
    ----------------------------------------------
    Alpha	(*) Complex sequence
    ----------------------------------------------
    PPC	(*) Complex sequence
    ----------------------------------------------
    MIPS	(*) Complex sequence
    ----------------------------------------------
    SPARC	XNOR	max	RRR	RRRI
    ----------------------------------------------
    68K	(*) Complex sequence
    -----------------------------------------------
    z80	(*) Complex sequence
    -----------------------------------------------
    HPPA	(*) Complex sequence

  Bitwize AND with complement of one operand

Вычисляет логическую функцию -	запрет

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	0
    0	1	|	0
    1	0	|	1
    1	1	|	0
    ------------------------------

    destination = source1 AND (NOT source2)

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

    ANDC(x,y) = AND(x, NOT(y))

 ------------------------------------------------------------------------------
o	AND with complement one operand

    x86	(*) Complex sequence
    ----------------------------------------------
    Alpha	(*) Complex sequence
    ----------------------------------------------
    PPC	ANDC	max	RRR
    ----------------------------------------------
    MIPS	(*) Complex sequence
    ----------------------------------------------
    SPARC	(*) Complex sequence
    ----------------------------------------------
    68K	(*) Complex sequence
    -----------------------------------------------
    z80	(*) Complex sequence
    -----------------------------------------------
    HPPA	(*) Complex sequence

  Bitwize OR  with complement of one operand

Вычисляет логическую функцию -	импликация

    destination = source1 IMP source2

    ------------------------------
    source1	source2	| destination
    ----------------+-------------
    0	0	|	1
    0	1	|	0
    1	0	|	1
    1	1	|	1
    ------------------------------

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

    ORC(x,y)  = OR(x, NOT(y))

 ------------------------------------------------------------------------------
o	OR with complement one operand

    x86	(*) Complex sequence
    ----------------------------------------------
    Alpha	(*) Complex sequence
    ----------------------------------------------
    PPC	ORC	max	RRR
    ----------------------------------------------
    MIPS	(*) Complex sequence
    ----------------------------------------------
    SPARC	(*) Complex sequence
    ----------------------------------------------
    68K	(*) Complex sequence
    -----------------------------------------------
    z80	(*) Complex sequence
    -----------------------------------------------
    HPPA	(*) Complex sequence
 ------------------------------------------------------------------------------


35.2.1.3. СДВИГИ И ВРАЩЕНИЯ

  Shift Arithmetical Left

 ------------------------------------------------------------------------------
o	Shift Arithetical Left

    x86	\
    Alpha	|--- alias to shift logical left on this architectures.
    PPC	|
    MIPS	/

  Shift Arithmetical Right

    destination = source >>> count

 ------------------------------------------------------------------------------
o	Shift Arithmetical Right

    x86	SAR	8	Rcl	RI
            16	Rcl	RI
            32	Rcl	RI
    --------------------------------------
    Alpha	SRA	64	RRR	RRI
    --------------------------------------
    PPC	SRAW	max	RRR
        SRAWI	max	RRI
    --------------------------------------
    MIPS	SRA	32	RRI
        SRAV	32	RRR
        DSRA	64	RRI
        DSRAV	64	RRR
    --------------------------------------
    SPARC	SRA	max	RRR	RRI
    --------------------------------------
    68K	ASR	8	RR	RI		(D-regs)
            16	RR	RI
            32	RR	RI
    ---------------------------------------
    z80	SRA	8	R
    ---------------------------------------
    MCS51	(*) Complex
    ---------------------------------------
    JVM	ISHR	32
        LSHR    64
    ---------------------------------------
    ARM	(*)	MOV wih operand2 = r ASR r
    ---------------------------------------
    SH4	SHAR	R		(shift by 1 bit)

  Shift Logical Left

    destination = source << count

 -------------------------------------------------------------------------------
o	Shift Logical Left

    x86	SHL	8	Rcl	RI
            16	Rcl	RI
            32	Rcl	RI
    --------------------------------------
    Alpha	SLL	64	RRR	RRI
    --------------------------------------
    PPC	SLW	max	RRR
    --------------------------------------
    MIPS	SLL	32	RRI
        SLLV	32	RRR
        DSLL	64	RRI
        DSLLV	64	RRR
    --------------------------------------
    SPARC	SLL	max	RRR	RRI
    --------------------------------------
    68K	LSL	8	RR	RI		(D-regs)
            16	RR	RI
            32	RR	RI
    --------------------------------------
    z80	SLA	8	R
    --------------------------------------
    HPPA	VEXTRUc	32	R,I5,R			(Extract Unsigned)
        VEXTRSc	32	R,I5,R			(Extract Signed)
        EXTRUc	32	R,R,I5,R		(Extract Unsigned)
        EXTRSc	32	R,R,I5,R		(Extract Signed)
    --------------------------------------
    IA-64	SHL	64	R1=R2,R3
                R1=R2,count(6) (Pop: dep.z r1=r2,count(6),
                               64-count(6).
    --------------------------------------
    MCS51	(*)  Complex sequence
    --------------------------------------
    JVM	ISHL	32
        LSHL	64
    ---------------------------------------
    ARM	(*)	MOV wih operand2 = r LSL r
    ---------------------------------------
    SH4	SHLL	R			(shift by 1 bit)
        SHLL2	R			(shift by 2 bits)
        SHLL8	R			(shift by 8 bits)
        SHLL16	R			(shift by 16 bits)

  Shift Logical Right

    destination = source >> count

 -------------------------------------------------------------------------------
o	Shift Logical Right

    x86	SHR	8	Rcl	RI
            16	Rcl	RI
            32	Rcl	RI
    --------------------------------------
    Alpha	SLR	64	RRR	RRI
    --------------------------------------
    PPC	SRW	max	RRR
    --------------------------------------
    MIPS	SRL	32	RRI
        SRLV	32	RRR
        DSRL	64	RRI
        DSRLV	64	RRR
    --------------------------------------
    SPARC	SRL	max	RRR	RRI
    --------------------------------------
    68K	LSR	8	RR	RI		(D-regs)
            16	RR	RI
            32	RR	RI
    --------------------------------------
    z80	SRL	8	R
    --------------------------------------
    HPPA	VSHDc	32	RRR		(Variable Shift Double)
        SHDc	32	RR,i5,R
    --------------------------------------
    IA-64	SHR	64	R1 = R3,R2		(Signed)
                R1 = R3, count(6)
        SHR.U	64	R1 = R3,R2		(Unsigned)
                R1 = R3, count(6)
    --------------------------------------
    MCS51	(*) Complex Sequence
    ---------------------------------------
    JVM	IUSHR	32
        LUSHR	64
    ---------------------------------------
    ARM	(*)	MOV wih operand2 = r LSR r
    ---------------------------------------
    SH4	SHLR	R			(shift by 1 bit)
        SHLR2	R			(shift by 2 bits)
        SHLR8	R			(shift by 8 bits)
        SHLR16	R			(shift by 16 bits)
 ------------------------------------------------------------------------------

  Rotates

Note:	Rotates usually makes then RRR or RR registers are the same.

    IA-64	SHLADD	R1=R2,count(2),R3	Shift Left + Add
        SHRP	R1=R2,R3,count(6)	Shift Right Pair

Rotates:

    ARM:	MOV  with operand2 = r ROR x (Rotate Right)

PPC:
    rotldi	ra,rs,n		rldicl	ra,rs,n,0
    rotrdi	ra,rs,n		rldicl	ra,rs,64-n,0
    rotld	ra,rs,rb	rldcl	ra,rb,rb,0
    sldi	ra,rs,n		rldicl	ra,rs,n,63-n

PowerPC

    srdi	Rx,Ry,N		=>	rldicl	Rx,Ry,64-n,n
    srwi	Rx,Ry,N		=>	rlwinm	Rx,Ry,32-n,n,31
    clrrwi	Rx,Ry,N		=>	rlwinm	Rx,Ry,0,0,31-n

Наиболее общего вида команды использует PowerPC:
(Это сразу и Shift и Rotate и Extract Bit).

  Rotate Left

    destination = source ROL count

 ---------------------------------------------------------------------------
o	Rotate Left

    x86	ROL	8	RR{CL}	RI
            16	RR{CL}	RI
            32	RR{CL}	RI
    ------------------------------------
    Alpha
    ------------------------------------
    PPC	RLWNM	max	RRRII		Rotate Left and AND with MASK
        RLWNM.	max	RRRII

    ------------------------------------
    MIPS
    ------------------------------------
    SPARC
    ------------------------------------
    HPPA
    ------------------------------------
    68K	ROL	8	RR	RI
            16	RR	RI
            32	RR	RI
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4

  Rotate Right

    destination = source ROR count

 ---------------------------------------------------------------------------
o	Rotate Right

    x86	ROR	8	RR{CL}	RI
            16	RR{CL}	RI
            32	RR{CL}	RI
    ------------------------------------
    Alpha
    ------------------------------------
    PPC
    ------------------------------------
    MIPS
    ------------------------------------
    SPARC
    ------------------------------------
    HPPA
    ------------------------------------
    68K	ROR	8	RR	RI
            16	RR	RI
            32	RR	RI
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4

  Rotate through Carry Left

    destination = source RCL count

 ---------------------------------------------------------------------------
o	Rotate throught Carry Left

    x86	RCL	8	RR{CL}	RI
            16	RR{CL}	RI
            32	RR{CL}	RI
    ------------------------------------
    Alpha
    ------------------------------------
    PPC
    ------------------------------------
    MIPS
    ------------------------------------
    SPARC
    ------------------------------------
    HPPA
    ------------------------------------
    68K	ROXL	8	RR	RI
            16	RR	RI
            32	RR	RI
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4

  Rotate through Carry Right

    destination = source RCR count

 ---------------------------------------------------------------------------
o	Rotate throught Carry Right

    x86	RCR	8	RR{CL}	RI
            16	RR{CL}	RI
            32	RR{CL}	RI
    ------------------------------------
    Alpha
    ------------------------------------
    PPC
    ------------------------------------
    MIPS
    ------------------------------------
    SPARC
    ------------------------------------
    HPPA
    ------------------------------------
    68K	ROXR	8	RR	RI
            16	RR	RI
            32	RR	RI

    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4


35.2.1.4. РАБОТА С ПАМЯТЬЮ

Работа с памятью - загрузка частей

Alpha:	Load 32-bit unsigned
        LDL
        LDU  EXTLL

  Load

    destination = Memory[EA](Size)

Пример когда размер памяти равен размера регистра

    destination = sign_extent(Memory[EA](Size))

Загрузка части с расширением знака.

    destination = zero_extent(Memory[EA](Size))

 ------------------------------------------------------------------------------
o	Load BYTE (8-bit)

    x86	MOV		R[Ar+Ir+Disp]
    -----------------------------------------
    Alpha	(*)	LDL/LDQ, then EXTBL  RRR RRI
    -----------------------------------------
    PPC	LBA	??
        LBAX	??
        LBZ		R[Ar]
        LBZX		R[Ar+Ir]
    ------------------------------------------
    MIPS	LB		R[Ar+Disp]
        LBU		R[Ar+Disp]
    ------------------------------------------
    SPARC	LDSB		R[Ar+Ar/Disp]		(signed)
        LDUB		R[Ar+Ar/Disp]		(unsigned)
    ------------------------------------------
    HPPA	LDB		Disp14(s,R),R
        LDBX		Ir(s,R)R
        LDBS		Disp5(s,R)R		(short)
    ------------------------------------------
    68K	MOVE		R[Ar+Disp]		(DA)
    ------------------------------------------
    z80	LD		R[Ar+Disp]
    ------------------------------------------
    IA-64	LD1.ldtype.ldhint	R1=R3     (no base update)
        LD1.ldtype.ldhint	R1=R3,R2  (base update)
        LD1.ldtype.ldhint	R1=R3,I9  (imm base update)
              (normal load)
            s	    (speculative load)
            a	    (advanced load)
            sa	    (speculative advanced load)
           c.nc	    (check load - no clear)
          c.clr     (check load - clear)
        c.clr.acq   (ordered check load - clear)
           acq      (ordered load)
           bias     (biased load)
              .ldhint
                  (Temporary locality level 1)
               nt1	    (No temporal locality level 1)
               nta	    (No temporal locality all levels)
        for SIGNED: one additional operation:
            SXT1	R1=R3
        for UNSIGNED:
            ZXT1	R1=R3
    -------------------------------------------
    MCS51	MOV	8	A,addr          (A8)
                A,@Ri
                Ri,addr
                A,@DPTR		(A16)
    --------------------------------------------
    JVM	BALOAD	8			(Load Byte from Array)
        CALOAD  8  	                (Load Char from Array)
    --------------------------------------------
    ARM	LDRccB	8	RM
        LDRccBT 8       RM      	(user-mode)
        LDRccSB 8       RM  	        (signed byte)
    ---------------------------------------------
    SH4	MOV.B		@-R,R
                @R+,R
                @R,R
 ------------------------------------------------------------------------------
o	Load WORD (16-bit)

    x86	MOV		R[Ar+Ir+Disp]
    ------------------------------------------
    Alpha	(*)	LDL/LDQ, then EXTWL/EXTWH RRR RRI
    ------------------------------------------
    PPC	LHA		R[Ar]
        LHAX		R[Ar+Ir]
        LHZ		R[Ar]
        LHZX		R[Ar+Ir]
    ------------------------------------------
    MIPS	LH		R[Ar+Disp]
        LHU		R[Ar+Disp]
    ------------------------------------------
    SPARC	LDSH		R[Ar+Ar/Disp]		(Signed)
        LDUH		R[Ar+Ar/Disp]		(Unsigned)
    ------------------------------------------
    HPPA	LDH		Disp14(s,R),R
        LDHX		Ir(s,R)R
        LDHS		Disp5(s,R)R		(short)
    ------------------------------------------
    68K	MOVE		R[Ar+Disp]		(DA)
    ------------------------------------------
    z80	LD		R[Ar+Disp]
    ------------------------------------------
    IA-64	LD2.ldtype.ldhint	R1=R3     (no base update)
        LD2.ldtype.ldhint	R1=R3,R2  (base update)
        LD2.ldtype.ldhint	R1=R3,I9  (imm base update)
        for SIGNED: one additional operation:
            SXT2	R1=R3
        for UNSIGNED:
            ZXT2	R1=R3
    ------------------------------------------
    JVM	SALOAD	16			(Load Word Array)
    ------------------------------------------
    ARM	LDRccH 		RM		(unsigned)
        LDRccSH         RM  	        (signed)
    ---------------------------------------------
    SH4	MOV.W		@-R,R
                @R+,R
                @R,R
 ------------------------------------------------------------------------------
o	Load DWORD (32-bit)

    x86	MOV		R[Ar+Ir+Disp]
    ------------------------------------------
    Alpha	LDL		R[Ar+Disp16]
    ------------------------------------------
    PPC	LWZ		R[Ar]
        LWZX		R[Ar+Ir]
    ------------------------------------------
    MIPS	LW		R[Ar+Disp]
        LWU		R[Ar+Disp]
    ------------------------------------------
    SPARC	LDSW		R[Ar+Ar/Disp]		(Signed) V9
        LD		R[Ar+Ar/Disp]		(Unsigned)
    ------------------------------------------
    HPPA	LDW		Disp14(s,R),R		(imm. index)
        LDWX		Ir(s,R)R		(reg index)
        LDWAX		R(R)R			(absolute address)
        LDWS		Disp5(s,R)R		(short)
        LDWAS		Disp5(s,R)R		(absolute short)
        LDWM		Disp14(s,R),R		(MODIFY BASE!!)
    ------------------------------------------
    68K	MOVE		R[Ar+Disp]		(DA)
    ------------------------------------------
    z80
    ------------------------------------------
    IA-64	LD4.ldtype.ldhint	R1=R3     (no base update)
        LD4.ldtype.ldhint	R1=R3,R2  (base update)
        LD4.ldtype.ldhint	R1=R3,I9  (imm base update)
        for SIGNED: one additional operation:
            SXT4	R1=R3
        for UNSIGNED:
            ZXT4	R1=R3
    -------------------------------------------
    JVM	IALOAD	32			(Load Array)
        ILOAD_0	32
        ILOAD_1 32
        ILOAD_2 32
        ILOAD_3 32
        ILOAD	32		NUM_STACK_POS
    -------------------------------------------
    ARM	LDRcc	32	RM
        LDRcc   32      RM              (user mode)
    ---------------------------------------------
    SH4	MOV.L		@-R,R
                @R+,R
                @R,R
 ------------------------------------------------------------------------------
o	Load QWORD (64-bit)

    x86
    ------------------------------------------
    Alpha	LDQ		R[Ar+Disp16]
        LDQ_U		R[Ar+Disp16]		(Unaligned)
    ------------------------------------------
    PPC	LD		R[Ar]
        LDX		R[Ar+Ir]
    ------------------------------------------
    MIPS	LD		R[Ar+Disp]
    ------------------------------------------
    SPARC	LDX		R[Ar+Ar/Disp]		V9
    ------------------------------------------
    68K
    ------------------------------------------
    z80
    ------------------------------------------
    IA-64	LD8.ldtype.ldhint	R1=R3     (no base update)
        LD8.ldtype.ldhint	R1=R3,R2  (base update)
        LD8.ldtype.ldhint	R1=R3,I9  (imm base update)

        LD8.fill.ldhint		R1=R3
        LD8.fill.ldhint		R1=R3,R2
        LD8.fill.ldhint		R1=R3,I9
    ------------------------------------------
    JVM	LALOAD	64			(Array)
        LLOAD_0	64
        LLOAD_1	64
        LLOAD_2	64
        LLOAD_3	64
        LLOAD	64		NUM_STACK_POS

  Store

    Memory[EA](Size) = source

    Memory[EA](Size) = Truncate(source, Size)

 ------------------------------------------------------------------------------
o	Store BYTE (8-bit)

    x86	MOV		R[Ar+Ir+Disp]
    -----------------------------------------
    Alpha	(*) INSBL  RRR RRI, then STL/STQ, may be preload
    -----------------------------------------
    PPC	STB		R[Ar]
        STBX		R[Ar+Ir]
    ------------------------------------------
    MIPS	SB		R[Ar+Disp]
    ------------------------------------------
    SPARC	STB		R[Ar+Ar/Disp]
    ------------------------------------------
    HPPA	STB		R,Disp14(s,R)
        STBS		R,Disp5(s,R)		(short)
    ------------------------------------------
    68K	MOVE		R[Ar+Disp]		(DA)
    ------------------------------------------
    z80	LD		R[Ar+Disp]
    ------------------------------------------
    IA-64	ST1.sttype.sthint	[R3] = R2
                    [R3] = R2, I9
            rel  (ordered store)
    ------------------------------------------
    MCS-51	MOV	8	addr,A          	(A8)
                 addr,Ri
                @Ri,A
                            @DPTR,A			(A16)
    -------------------------------------------
    JVM	BASTORE	8       			(Array)
        CASTORE	8	                        (Array)
    -------------------------------------------
    ARM	STRccB	8	RM
        STRccBT	8				(user mode)
    ---------------------------------------------
    SH4	MOV.B		R,@-R
                R,@R+
                R,@R
 ------------------------------------------------------------------------------
o	Store WORD (16-bit)

    x86	MOV		R[Ar+Ir+Disp]
    ------------------------------------------
    Alpha	(*) INSWH/INSWL, then STL/STQ, may be preload
    ------------------------------------------
    PPC	STH		R[Ar]
        STHX		R[Ar+Ir]
    ------------------------------------------
    MIPS	SH		R[Ar+Disp]
    ------------------------------------------
    SPARC	STH		R[Ar+Disp]
    ------------------------------------------
    HPPA	STH		R,Disp14(s,R)
        STHS		R,Disp5(s,R)		(short)
    ------------------------------------------
    68K	MOVE		R[Ar+Disp]		(DA)
    ------------------------------------------
    z80	LD		R[Ar+Disp]
    ------------------------------------------
    IA-64	ST2.sttype.sthint	[R3] = R2
                    [R3] = R2, I9
            rel  (ordered store)
    ------------------------------------------
    JVM	SASTORE	16				(Array)
    ------------------------------------------
    ARM	STRccH	16	RM
    ---------------------------------------------
    SH4	MOV.W		R,@-R
                R,@R+
                R,@R
 ------------------------------------------------------------------------------
o	Store DWORD (32-bit)

    x86	MOV		R[Ar+Ir+Disp]
    ------------------------------------------
    Alpha	STL		R[Ar+Disp16]
    ------------------------------------------
    PPC	STW		R[Ar]
        STWX		R[Ar+Ir]
    ------------------------------------------
    MIPS	SW		R[Ar+Disp]
    ------------------------------------------
    SPARC	ST		R[Ar+Ar/Disp]
    ------------------------------------------
    HPPA	STW		R,Disp14(s,R)
        STWS		R,Disp5(s,R)		(short)
        STWAS		R,R(R)			(absolute short)
        STWM		R,Disp14(s,R)		(MODIFY BASE REG)
    ------------------------------------------
    68K	MOVE		R[Ar+Disp]		(DA)
    ------------------------------------------
    z80
    ------------------------------------------
    IA-64	ST4.sttype.sthint	[R3] = R2
                    [R3] = R2, I9
            rel  (ordered store)
    ------------------------------------------
    JVM	IASTORE	32		(Array)
        ISTORE_0
        ISTORE_1
        ISTORE_2
        ISTORE_3
        ISTORE		NUM_STACK_POS
    ------------------------------------------
    ARM	STRcc 		RM
        STRccT          RM			(user mode)
    ---------------------------------------------
    SH4	MOV.L		R,@-R
                R,@R+
                R,@R
 ------------------------------------------------------------------------------
o	Load QWORD (64-bit)

    x86
    ------------------------------------------
    Alpha	STQ		R[Ar+Disp16]
        STQ_U		R[Ar+Disp16]		(Unaligned)
    ------------------------------------------
    PPC	STD		R[Ar]
        STDX		R[Ar+Ir]
    ------------------------------------------
    MIPS	SD		R[Ar+Disp]
    ------------------------------------------
    SPARC	STX		R[Ar+Disp]		V9
    ------------------------------------------
    68K
    ------------------------------------------
    z80
    ------------------------------------------
    IA-64	ST8.sttype.sthint	[R3] = R2
                    [R3] = R2, I9
            rel  (ordered store)
    -------------------------------------------
    JVM	LASTORE	64			(Array)
        LSTORE_0
        LSTORE_1
        LSTORE_2
        LSTORE_3
        LSTORE		NUM_STACK_POS

  Load Unaligned

 ------------------------------------------------------------------------------
o	Load Unaligned

    x86	(*) No need
    ------------------------------------
    Alpha	LDQ_U	64	RM

THIS SECTION IS UNDER CONSTRUCTION

  Store unaligned

THIS SECTION IS UNDER CONSTRUCTION

 ------------------------------------------------------------------------------
o	Store Unaligned

    x86	(*) No need
    ------------------------------------
    Alpha	STQ_U	64	RM

  Prefetch

    Cache[EA] = Mem[EA]	// Async

SPARC prefetch functions
    0	for several reads
    1	for one read
    2	for several writes
    3	for one write
    4	page

 ---------------------------------------------------------------------------
o	Prefetch

    x86     PREFETCH0	M
        PREFETCH1	M
        PREFETCH2	M
        PREFETCHNTA	M
    ------------------------------------
    Alpha	FETCH
        FETCH_M

    ------------------------------------
    PPC	DCBT
        DCBTST
    ------------------------------------
    MIPS	PREF
        PREFX
    ------------------------------------
    SPARC	PREFETCH -	MF	(F = function)
    ------------------------------------
    HPPA	(*)	LDD ,r0
            LDW ,r0
    ------------------------------------
    68K
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4

  Memory Barrier

 ---------------------------------------------------------------------------
o	Memory Barrier

    x86	MFENCE
    ------------------------------------
    Alpha	WMB
    ------------------------------------
    PPC	MBAR
        MSYNC
    ------------------------------------
    MIPS	SYNC
    ------------------------------------
    SPARC	MEMBAR
    ------------------------------------
    HPPA	SYNC
    ------------------------------------
    68K
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4

  Move between registers

    destination = source

На RISC архитектурах может делаться через AND, OR итд с регистром
всегда содержащим 0.

Например SPARC:

    mov	%r5,%r6	  =>	or	%g0,%r5,%r6

 ---------------------------------------------------------------------------
o	Move between registers

    x86	MOV	8	RR
            16	RR
            32	RR
    ------------------------------------
    Alpha	(*)	BIS r31, ...
    ------------------------------------
    PPC	(*)	OR  rs,rs,rd
    ------------------------------------
    MIPS	(*)	ADD  with r0
    ------------------------------------
    SPARC   (*)	OR with r0
    ------------------------------------
    HPPA	(*)	OR with r0
    ------------------------------------
    68K	MOVE	RR
        MOVEA	R{A}R		To address register
    ------------------------------------
    VAX-11
    ------------------------------------
    IA-64	MOV	64	R1=R2		(Pop: adds R1=0,R3)
    ------------------------------------------
    MCS51	MOV	8	Ri,A
                A,Ri
    ------------------------------------------
    ARM	MOVcc	32	RR
    ------------------------------------------
    SH4	MOV		RR

 --------------------------------------------------------------------------------
o	Load Offset

    Alpha	LDA	RRDisp16
        LDAH	RRDisp(31..16)
    ------------------------------------------
    HPPA	LDO	Disp14(R),R
    ------------------------------------------
    x86	LEA

  Load Immediate Value

    destination = immediate_cosnt

    destination = sign_extent(immediate_const)

Загрузка 32-битного числа в регистр на SPARC v8

    set	value,reg

        sethi	%hi(value),reg
        or	%g0, %lo(value), reg

Для SPARC v9 (64-разрядная архитектура)

    setuw	value,reg

        sethi 	%hi(value),reg
        or	reg,%lo(value),reg

    setsw	value,reg

        sethi	%hi(value),reg
        or	reg,%lo(value),reg
        sra	reg,%g0,reg

Для 64-разрядного значения на SPARC V9

    setx	value,reg,rd

        sethi	%uhi(value), reg
        or	reg, %ulo(value), reg
        sllx	reg,32,reg		! shift on 32 bit
        sethi	%hi(value),rd
        or	rd, reg, rd
        or	rd, %lo(value), rd

 --------------------------------------------------------------------------------
o	Load Immediate Value

    HPPA	LDIL	Imm21,R			(Load Immediate Low  part reg)
    ------------------------------------------
    x86	MOV	8	RI	MI
            16	RI	MI
            32	RI	MI
    ------------------------------------------
    IA-64	MOV	64	R1 = I22	(Pop: addl R1=I22,r0)
        MOVL	64	R1 = I64
    ------------------------------------------
    MCS51	MOV	8	Ri,I8
                A,I8
    ------------------------------------------
    JVM 		previously
        ICONST_M1	32
        ICONST_0
        ICONST_1
        ICONST_2
        ICONST_3
        ICONST_4
        ICONST_5
        LCONST_0        64
        LCONST_1
        BIPUSH		8	IMM8		(Push Byte)
        SIPUSH		16	IMM16		(Push Word)
        LDC1		vary	CONST_IDX8	(From Constant Pool)
        LDC2		vary	CONST_IDX16	(From Constant Pool)
        LDC2W		vary	CONST_IDX16	(LONG or DOUBLE)
    -------------------------------------------
    ARM 	(*) Complex code based on MOVcc
    -------------------------------------------
    SH4	MOV		RI

    destination[high_part] = immediate_const
    destination[low_part]  = source[low_part]

 -------------------------------------------------------------------------------
o	Load High Part Register

    x86	(*) No need
    ------------------------------------
    Alpha	LDAH
    ------------------------------------
    PPC	ADDIS
    ------------------------------------
    MIPS	LUI
    ------------------------------------
    SPARC   SETHI		RI{S22}
    ------------------------------------
    HPPA	LDIL
    ------------------------------------
    68K	(*) No need
    ------------------------------------
    VAX-11	(*) No need
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4


35.2.1.4.2. СЕМАФОРНЫЕ ОПЕРАЦИИ

  Semaphore Operations

Типовые опрерации для CISC машин:

Exchange:

    temp = source
    Start Bus Lock
    [
        source = Memory[EA]
        Memory[EA] = temp
    ]
    Finish Bus Lock

Exchange and Add:

    Start Bus Lock
    [
        temp = Memory[EA]
        Memory[EA] = temp + source
    ]
    Finish Bus Lock
    destination = temp

Compare and Exchange

    Start Bus Lock
    [
        temp = Memory[EA]
        if (temp == comparand)
        {
            Memory[EA] = source
        }
    ]
    destination = temp

Типовые операции для RISC машин:

    lock_flag = 1
    lock_address = EA
    destination = Memory[EA]

    Each bus cycle
    [
        if (Bus.Address == EA)
        {
            lock_flag = 0;
        }
    ]

    if (lock_flag == 1)
    {
        Memory[EA] = source
    }
    destination = lock_flag
    lock_flag = 0

Alpha:
        LDL_L	Reg, Mem	! 4-bytes
    LDQ_L	Reg, Mem	! 8-bytes

    Reg = Memory[EA];
    lock_flag = 1;
    locked_physical_address = EA

    STL_C	Reg, Mem	! 4-bytes
    STQ_C	Reg, Mem	! 8-bytes

    if (lock_flag == 1)
    {
        Memory[EA] = Reg
    }
    Reg = lock_flag
    lock_flag = 0;

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

Пример реализации обычных примитивов для PowerPC:

# Atomic Fetch
#		r3	- address
#		r4	- data

    loop:	lwarx	r4,0,r3		# load
        stwcx.	r4,0,r3		# store old value if still reserved
        bne-	loop

# Fetch and Store (Exchange)
#               r3	- address
#		r4	- new value
#		r3	- old value

    loop:	lwarx	r5,0,r3		# load
        stwcx.	r4,0,r3		# store if still reserved
        bne-	loop

# Fetch and Add
#		r3	- address
#		r4	- value to add
#		r5	- old value

    loop:	lwarx	r5,0,r3 	# read
        add	r0,r4,r5	# modify
        stwcx.	r0,0,r3		# write
        bne-	loop

# Fetch and And
#		r3	- address
#		r4	- value to and
#		r5	- old value

    loop:	lwarx	r5,0,r3 	# read
        and	r0,r4,r5	# modify
        stwcx.	r0,0,r3		# write
        bne-	loop

# Test and Set
#		r3	- address
#		r4	- new value (!=0)
#		r5	- old value

    loop:	lwarx	r5,0,r3
        cmpwi	r5,0
        bne-	$+12
        stwcx.	r4,0,r3
        bne-	loop

# Compare and Swap
#		r3	- address
#		r4	- comparant / old value
#		r5	- new value

    loop:	lwarx	r6,0,r3
        cmpw	r4,r6
        bne-	exit
        stwcx.	r5,0,r3
        bne-	loop
    exit:	mr	r4,r6

 ------------------------------------------------------------------------------
o	Semaphores Support tools

    x86	XCHG	8	RM
            16	RM
            32	RM
    ------------------------------------------
    Alpha	LDL_L	32	R[Ar+Disp16]
        STL_C	32	R[Ar+Disp16]
        LDQ_L	64	R[Ar+Disp16]
        STQ_L	64	R[Ar+Disp16]
    ------------------------------------------
    PPC	LWARX
        STWCX
    ------------------------------------------
    MIPS	LL	32	R[Ar+Disp16]
        SC	32	R[Ar+Disp16]
        LLD	64	R[Ar+Disp16]
        SCD	64	R[Ar+Disp16]
    ------------------------------------------
    SPARC	(*) Need to seek
        CASA
        CASX
    ------------------------------------------
    HPPA	LDCWX	32	Disp14(s,R)R		(Load & Clear)
        LDCWS	32	Disp5(s,R)R		(Load & Clear short)

    ------------------------------------------
    68K	TAS	8	?			(EA) (Test and Set)
        TST	8	?			(EA) (Test)
            16	?
            32	?
        CAS	RRM				(CMPXCHG   analog)
        CAS2	RRM				(CMPXCHG8B analog)
    ------------------------------------------
    z80	(None tools for support semaphores)
    ------------------------------------------
    IA-64	CMPXCHG1	8	R1 = [R3],R2,ar.ccv	(~CMPXCHG)
        CMPXCHG2       16	R1 = [R3],R2,ar.ccv
        CMPXCHG4       32	R1 = [R3],R2,ar.ccv
        CMPXCHG8       64	R1 = [R3],R2,ar.ccv

        FETCHADD4.sem.ldhint	R1 = [R3],inc(3)		(~XADD)
        FETCHADD8.sem.ldhint	R1 = [R3],inc(3)
              acq
              rel
        XCHG1.ldhint		R1 = [R3],R2		(~XCHG)
        XCHG2.ldhint		R1 = [R3],R2
        XCHG3.ldhint		R1 = [R3],R2
        XCHG4.ldhint		R1 = [R3],R2
    --------------------------------------------
    MCS51	XCH	8	A,addr		(A8)
                A,@Ri
 -------------------------------------------------------------------------------
Note:	LMW/STMW (PPC)  - Load Multiple Words/Store Multiple Words.
    STBYS	 (HPPA) - Store bytes shorts

    MCS-51 architecture - lot of memory,memory loads/store

    Signed and Unsigned Loading.
    Immediate Data Loading.
    Add Here all Load/Store & Modify Base Register


35.2.1.5. ПЕРЕСЫЛКА И ПРЕОБРАЗОВАНИЕ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

    destination = sign_extent(source)

Например на SPARC:

    signx	rd,rd

        sra	rs,%g0,rd

    destination = zero_extent(source)

 -------------------------------------------------------------------------------
o	BYTE -> WORD (Signed Extend/Unsigned Extend)

    x86	MOVSX		RR		(signed)
        MOVZX		RR		(unsigned)
    -----------------------------------------
    Alpha	EXTBL		RRR	RRI
    -----------------------------------------
    PPC	EXTSB		RR
    -----------------------------------------
    MIPS	(*) 				(Throught memory ????)
    -----------------------------------------
    SPARC	(*)
    -----------------------------------------
    68K	EXT		R		(signed)
    -----------------------------------------
    z80
    -----------------------------------------
    JVM	(*) During Load only
 -------------------------------------------------------------------------------
o	WORD -> DWORD (Signed Extend/Unsigned Extend)

    x86	MOVSX		RR		(signed)
        MOVZX		RR		(unsigned)
    -----------------------------------------
    Alpha	EXTWH		RRR	RRI
        EXTWL		RRR	RRI
    -----------------------------------------
    PPC	EXTSH		RR		(signed)
    -----------------------------------------
    MIPS	(*)				(Throught memory ????)
    -----------------------------------------
    SPARC 	(*)
    -----------------------------------------
    68K	EXT		R		(signed)
    -----------------------------------------
    z80
    -----------------------------------------
    JVM	(*) During Load only
 -------------------------------------------------------------------------------
o	DWORD -> QWORD (Signed Extend/Unsigned Extend)

    x86	(*)
    ------------------------------------------
    Alpha	EXTLL		RRR	RRI
        EXTLH		RRR	RRI
    ------------------------------------------
    PPC	(*)
    ------------------------------------------
    MIPS	(*)
    -----------------------------------------
    SPARC	(*)
    -----------------------------------------
    68K	(*)
    -----------------------------------------
    z80
    -----------------------------------------
    JVM	I2L				(dword -> qword)
        L2I				(qword -> dword)
 -------------------------------------------------------------------------------
o	BYTE -> DWORD (Signed Extend/ Unsigned Extend)

    x86	MOVSX		RR
        MOVZX		RR
    -------------------------------------------
    Alpha	EXTBL		RRR	RRI
    -------------------------------------------
    PPC	EXTSB		RR
    -------------------------------------------
    MIPS	(*) Throught memory ????
    -------------------------------------------
    SPARC	(*)
    -------------------------------------------
    68K	(*) complex sequence
    -------------------------------------------
    z80	(*) complex sequence
    -------------------------------------------
    JVM	(*) During Load only
 ------------------------------------------------------------------------------
Note:	HPPA architecture use:
        VEXTRU/VEXTRS/EXTRU/EXTRS (for extract)
        VDEP/DEP/VDEPI/DEPI/ZVDEP/ZDEP/ZVDEPI (for deposit)
        This instruction fetches/extract variables as bit
        string with/without sign extension.
        Good for Type conversion. But in RISC cpu's usually type
        conversion proceed only then store var in memory

Note:	Need also Big-Little Endian Conversion operations

Note:	To Lower-size conversions (JVM)
        INT2BYTE
        INT2CHAR
        INT2SHORT


35.2.1.6. СРАВНЕНИЯ И УСЛОВНЫЕ ПЕРЕХОДЫ

                        Alpha	MIPS	HPPA	PPC	SPARC	IA-64
Return address register		any	r31	r2,r31	link	r31

Типовой branch по флагам:

    if (Logical_Function(Flags))
    {
        Jump
    }

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

Пример условий и комбинаций флагов для x86:
 --------------------------------------------------------------------------
Abbr	 Unsigned Signed Condition		Description
 --------------------------------------------------------------------------
A/NBE	   >		 (CF==0) and (ZF==0)    Above/Not Below Equal
AE/NB/NC   > =		  CF==0	 		Above Equal/Not Below/Not Carry
B/NAE/C	   <		  CF==1			Below/Not Above Equal/Carry
BE/NA	   < =		 (CF==1) or  (ZF==1)	Below Equal/Not Above
E/Z	   ==     ==	  ZF==1			Equal/Zero
NE/NZ	   !=	  !=	  ZF==0			Not Equal/Not Zero
G/NLE		  >      (SF==OF) and (ZF==0) 	Greater/Not Less Equal
GE/NL		  >=     (SF==OF)		Greater Equal/Not Less
L/NGE		  <       SF!=OF		Less/Not Greater Equal
LE/NG		  <=	 (SF!=OF) or (ZF==1)	Less Equal/Not Greater
NO			  OF==0			Not Overflow
O			  OF==1			Overflow
NP/PO			  PF==0			No Parity/Parity Odd
P/PE			  PF==1			Parity/Parity even
NS			  SF==0			No Sign
S			  SF==1			Sign
 ---------------------------------------------------------------------------

Мнемоники переходов по флагам и их комбинациям
--------------------------------------------------------------------------------------
Unsigned Signed	x86	Alpha	PPC*	MIPS	SPARC	68K	HPPA	IA64	ARM
--------------------------------------------------------------------------------------
  >         	JA      ---     BGT   	---     BGU     BHI     ---    	---     BHI
        JNBE				BPGU
  > =           JAE     ---     BGE     ---     BCC	BCC     ---     ---     BCC
        JNB             BNL             BPCC                            BLO
        JNC
  <		JB      ---     BLT     ---     BCS     BCS     ---     ---     BCS
        JNAE                            BPCS    BLO                     BHS
        JC
  < =          	JBE     ---     BLE     ---     BLEU    BLS     ---     ---     BLS
        JNA             BNG             BPLEU
  ==      ==	JE      ---     BEQ     ---     BE      BEQ     ---     ---     BEQ
        JZ                              BPE
  !=      !=	JNE	---	BNE	---	BNE     BNE     ---     ---     BNE
        JNZ                             BPNE
          >	JG      ---     BGT     ---     BG      BGT     ---     ---     BGT
        JNLE                            BPG
          >=	JGE     ---     BGE     ---     BGE     BGE     ---     ---     BGE
        JNL             BNL             BPGE
          <	JL      ---     BLT     ---     BL      BLT     ---     ---     BLT
        JNGE                            BPL
          <= 	JLE     ---     BLE     ---     BLE     BLE     ---     ---     BLE
        JNG             BNG             BPLE
    S == 0	JNS	---	---	---	BNEG    BPL     ---     ---     BPL
                        BPNEG
    S == 1      JS	---	---	---	BPOS    BMI     ---     ---     BMI
                            BPPOS
    O == 0	JNO	---	BNS	---	BVC     BVC     ---     ---     BVC
                        BPVC
    O == 1	JO	---	BSO	---	BVS     BVS     ---     ---     BVS
                        BPVS
    P == Even	JP 	---     --- 	---	---	---     ---     ---     ---
        JPE
    P == Odd	JNP     ---     ---     ---     ---     ---     ---     ---     ---
        JPO
--------------------------------------------------------------------------------------

Замечания:

PPC:    Реально есть варианты команды условного перехода:	BC,BCA,BCL,BCLA

    В CRi есть биты: LT,GT,EQ,SO.
    По каждому можно перейти если он установлен, либо снят.
    А значение зависит от того была ли предидущая операция signed
     или unsigned.
    Например для сравнений надо использовать следущие мнемоники
        Signed compare: 	CMP, CMPI
        Unsigned compare:       CMPL, CMPLI	(Logical compare)

SPARC:	Форма  Bxx  - это обычный условный переход
           BPxx - переход с предсказанием (branch with prediction)

68K:	Есть еще серия команд DBcc reg,label
    которые имеют теже коды условий, но используются для циклов
    таким образом изменяя значения регистра

        if (condition == false)
        {
            reg--
            if (reg != -1) Jump
        }

Branch по сравнению с нулем

    if (Specified_Compare(source, 0))
    {
        Jump
    }

Переход по сравнению регистра с 0
--------------------------------------------------------------------------------------
Unsigned Signed	x86	Alpha	PPC	MIPS	SPARC	68K	HPPA	IA64	ARM
--------------------------------------------------------------------------------------
  >         	--						(*)
  > =           --                                              (*)
  <		--                                              (*)
  < =          	--                                              (*)
  ==      ==	--	BEQ     		BRZ             (*)
  !=      !=	--      BNE                     BRNZ            (*)
          >	--      BGT             BGTZ    BRGZ            (*)
                    BGTZL

          >=	--      BGE         	BGEZ    BRGEZ           (*)
                    BGEZAL
                    BGEZALL
                    BGEZL
          <	--      BLT             BLTZ    BRLZ            (*)
                    BLTZAL
                    BLTZALL
                    BLTZL
          <= 	--      BLE             BLEZ    BRLEZ           (*)
                    BLEZL
--------------------------------------------------------------------------------------
Замечния:

MIPS:	L - Likely (execute delay slot only if branch is taken)
    AL - and link (i.e. it's not jump, but call)

HPPA:   Данная операция может быть сделана с помощью команды
    Compare with Immediate and Branch (CMPIBcc), с использованием
    0 в качестве immediate операнда.
    (Смотри коды условий ниже в разделе - переход по сравнению двух
     регистров)

Branch по сранению регистров

    if (Specified_Compare(source1, source2))
    {
        Jump
    }

Переход по сравнению двух регистров
--------------------------------------------------------------------------------------
Unsigned Signed	x86	Alpha	PPC	MIPS	SPARC	68K	HPPA	IA64	ARM
--------------------------------------------------------------------------------------
  >         	---	     		                        CMPB>>
  > =           ---                                             CMPB>>=
  <		---                                             CMPB<<
  < =          	---                                             CMPB<<=
  ==      ==	---	                BEQ                     CMPB=
                    BEQL
  !=      !=	---			BNE                     CMPB<>
                    BNEL
          >	---                                             CMPB>
          >=	---                                             CMPB>=
          <	---                                             CMPB<
          <= 	---                                             CMPB<=
   Overflow	---						CMPBSV
  Non Overflow	---						CMPBNSV
    Even        ---						CMPBEV
    Odd		---						CMPBOD
--------------------------------------------------------------------------------------
Замечания:

HPPA:	Реально еще есть команды типа
    CMPIB	Compare Immediate and Branch
    ADDB	Add and Branch
    ADDIB	Add Immediate and Branch

Branch по младшему биту регистра

    if (Low_Bit(source) == Desired_Value)
    {
        Jump
    }

Branch по биту регистра
--------------------------------------------------------------------------------------
        x86	Alpha	PPC	MIPS	SPARC	68K	HPPA	IA64	ARM
--------------------------------------------------------------------------------------
 ==0         	--	BLBC                                    BB>=
 ==1		--	BLBS                                    BB<
--------------------------------------------------------------------------------------
Замечания:

Alpha: только младший бит
HPPA:  любой бит регистра

TODO: Специальный случай с PowerPC
Condition register PPC
    mtcrf	mask, rS		rS and mask -> CR
    mfcr	rD			CR -> rD
    mcrxr	crfD			XER[3:0] -> CRi
    mcrf	crfD, crfS		CRi -> CRj
    crand	crD, crA, crB
    cror
    crxor
    crnand
    crnor
    creqv
    crandc
    crorc

  Compare

    Set_Flags(source1 -  source2)

Compare on SPARC делается как

    cmp	rs,reg_imm

        subcc	rs,reg_imm,%g0

    ! subcc - subtract and set flag,
    !	 r0 - всегда равен нулю

 ------------------------------------------------------------------------------
o	Arithmetical Comparing

    x86	CMP	8	RR	RI
            16	RR	RI
            32	RR	RI
    ---------------------------------------
    Alpha  (*) some strange algorithm, based on:
        CMPEQ	32/64	RRR	RRI		(equal)
        CMPLE	32/64	RRR	RRI		(signed:less-equal)
        CMPLT	32/64	RRR	RRI		(signed:less)
        CMPULE	32/64	RRR	RRI		(unsigned:less-equal)
        CMPULT	32/64	RRR	RRI		(unsigned:less)
    ---------------------------------------
    PPC	CMP	32	[CR]RR			(Signed)
            64	[CR]RR			(Signed)
        CMPI	32	[CR]RI			(Signed)
            64	[CR]RI			(Signed)
        CMPL	32	[CR]RR			(Unsigned)
            64	[CR]RR			(Unsigned)
        CMPLI	32	[CR]RI			(Unsigned)
            64	[CR]RR			(Unsigned)
    ----------------------------------------
    MIPS	(*) see Conditional Jumps
    ----------------------------------------
    SPARC	SUBCC	max	RRR	RRI
    ----------------------------------------
    68K	CMP	8	RR			(D-regs)
            16	RR
            32	RR
        CMPA	16	RR			(A-regs)
            32	RR
        CMPI	8	RI			(D-,A- regs).
            16	RI
            32	RI
    ----------------------------------------
    z80	CP	8	AR	AI
    ----------------------------------------
    HPPA	COMBT		RR,PREL(17)	(Compare, branch if true)
        COMBF		RR,PREL(17)	(Compare, branch if false)
        COMIBT		R,Im5,PREL(17)	(Compare, branch if true)
        COMIBF		R,Im5,PREL(17)	(Compare, branch if false)
        ADDBT		RR,PREL(17)	(Add, branch if true)
        ADDBF		RR,PREL(17)	(Add, branch if false)
        ADDIBT		R,Im5,PREL(17)	(Add, branch if true)
        ADDIBF		R,Im5,PREL(17)	(Add, branch if false)
        BVBc		n,R,PREL(17)    (Branch on variable bit)
        BBc		n,RR,PREL(17)   (branch on bit)
    ==>	COMCLRc	 32	RRR		Compare and clear
        COMICLRc 32	I11,RR
    ------------------------------------------
    IA-64	CMP.crel.ctype	64 P1,P2=R1,R2	Compare Registers
    (both)	    eq	  64 P1,P2=I8,R
            ne	 unc	64 P1,P2=r0,R
        (signed)    lt	 or	64 P1,P2=R,r0
            le   and
            gt	 or.andcm
            ge 	 orcm
    (unsigned)  ltu	 andcm
            leu	 and.orcm
            gtu
            geu
        CMP4.crel.ctype 32  P1,P2=R1,R2	Compare Lower DWORD of operds.
                   32  P1,P2=I8,R
                32  P1,P2=r0,R
                32  P1,P2=R,r0
    ----------------------------------------
    JVM	LCMP	64			(See other in jumps)
    ----------------------------------------
    ARM	CMPcc		32	RR
                    RI
        CMNcc		32	RR      (compare negative)
                    RI
    ----------------------------------------
    SH4	CMP/EQ			RR
        CMP/HS			RR
        CMP/HI			RR
        CMP/GT			RR
        CMP/PZ			RR
        CMP/PL			RR

  Logical Compare

    Set_Flags(source1 AND source2)

Logical compare на SPARC делается как:

    tst	reg1,reg2

        orcc	reg1,reg2,%g0

 -------------------------------------------------------------------------------
o	Logical Comparing

    x86	TEST	8	RR	RI
            16	RR	RI
            32	RR	RI
    -----------------------------------------
    Alpha (*)    complex sequence
    -----------------------------------------
    PPC   (*)    complex sequence
    -----------------------------------------
    MIPS  (*)    complex sequence, based on conditional Jumps
    -----------------------------------------
    SPARC	ANDCC	max	RRR	RRI
    -----------------------------------------
    68K   (*)    complex sequence
    -----------------------------------------
    z80   (*)    complex sequence
    -----------------------------------------
    IA-64	CMP.crel.ctype
    -----------------------------------------
    ARM	TSTcc	32	RR	RI
        TEQcc	32	RR	RI
    -----------------------------------------
    SH4	TST		RR

  Jump if carry

    if (CF == 1)
    {
        Jump
    }

 -------------------------------------------------------------------------------
o	Jump Carry  (Unsigned >)

    x86	JC		REL(8,16,32)
    ------------------------------------------
    Alpha  (*) complex sequence
    ------------------------------------------
    PPC	BC 		PREL(16)		[CR.GT]:true
    ------------------------------------------
    MIPS   (*)
    ------------------------------------------
    SPARC	BGU		PREL(?)
    ------------------------------------------
    68K	BCS		PREL(8,16,32)
    ------------------------------------------
    z80	JR 	C	PREL(8)
        JP	C	ADDR(16)
    ------------------------------------------
    HPPA	MOVB	??	R1,R2,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    ------------------------------------------
    MCS51	JC		REL
    ------------------------------------------
    SH4	(*)	use BT/BF

  Jump if no carry

    if (CF == 0)
    {
        Jump
    }

 -------------------------------------------------------------------------------
o	Jump No Carry (Unsigned <=)

    x86	JNC		REL(8,16,32)
    ------------------------------------------
    Alpha (*)
    ------------------------------------------
    PPC	BC 		PREL(16)		[CR.GT]:false
    ------------------------------------------
    MIPS  (*)
    ------------------------------------------
    SPARC	BLEU		PREL(?)
    ------------------------------------------
    68K	BCC		PREL(8,16,32)
    ------------------------------------------
    z80	JR	NC	PREL(8)
        JP	NC	ADDR(16)
    ------------------------------------------
    HPPA	MOVB	??	R1,R2,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    -------------------------------------------
    MCS51	JNC		REL
    ------------------------------------------
    SH4	(*)	use BT/BF

  Jump if Zero

    if (ZF == 1)
    {
        Jump
    }

 -------------------------------------------------------------------------------
o	Jump Zero  (Signed/Unsigned = )

    x86	JZ		REL(8,16,32)
    ------------------------------------------
    Alpha	BEQ		R.PREL(20)		(if Reg == 0)
    ------------------------------------------
    PPC	BC  		PREL(16)		[CRi.EQ]:true
    ------------------------------------------
    MIPS	BEQ		RR.PREL(18)		(if R1 = R1)
    ------------------------------------------
    SPARC	BE		PREL(?)
    ------------------------------------------
    68K	BEQ		PREL(8,16,32)
    ------------------------------------------
    z80	JR	Z	PREL(8)
        JP	Z	ADDR(16)
    ------------------------------------------
    HPPA	MOVB	=	R1,R2,PREL(17)
        MOVIB	=	R1,Imm5,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    ------------------------------------------
    MCS51	JZ		REL
    ------------------------------------------
    JVM	IFEQ		32	REL16	(Test Word on stack 0)
        IF_ICMPEQ       32	REL16	(Compare 2 words)
    ------------------------------------------
    SH4	(*)	use BT/BF

  Jump if no zero

    if (ZF == 0)
    {
        Jump
    }

 -------------------------------------------------------------------------------
o	Jump No Zero (Signed/Unsigned !=)

    x86	JNZ		REL(8,16,32)
    -------------------------------------------
    Alpha	BNE		R.PREL(20)		(if Reg != 0)
    -------------------------------------------
    PPC	BC  		PREL(16)		[CRi.EQ]:false
    -------------------------------------------
    MIPS	BNE		RR.PREL(18)		(if R1 != R2)
    -------------------------------------------
    SPARC	BNE		PREL(?)
    -------------------------------------------
    68K	BNE		PREL(8,16,32)
    ------------------------------------------
    z80	JR	NZ	PREL(8)
        JP	NZ	ADDR(16)
    ------------------------------------------
    HPPA	MOVB	<>	R1,R2,PREL(17)
        MOVIB	<>	R1,Imm5,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    ------------------------------------------
    MSC51	JNZ		REL
    ------------------------------------------
    JVM	IFNE		32	REL16	(Test Word on stack 0)
        IF_ICMPNE       32	REL16	(Compare 2 words)
    ------------------------------------------
    SH4	(*)	use BT/BF

  Jump Great

 -------------------------------------------------------------------------------
o	Jump Great	(Signed >)

    x86	JG		REL(8,16,32)
    -------------------------------------------
    Alpha	BGT		R.PREL(20)		(if Reg > 0)
    --------------------------------------------
    PPC	BC   	  	PREL(16)		[CRi.GT]:true
    --------------------------------------------
    MIPS	BGTZ		R.PREL(18)		(if Reg > 0)
    --------------------------------------------
    SPARC	BG		PREL(?)
    --------------------------------------------
    68K	BGT		PREL(8,16,32)
    --------------------------------------------
    z80	(*)	Complex sequence
    ------------------------------------------
    HPPA	MOVB	>	R1,R2,PREL(17)
        MOVIB	>	R1,Imm5,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    ------------------------------------------
    JVM	IFGT		32	REL16	(Test Word on stack 0)
        IF_ICMPGT       32	REL16	(Compare 2 words)
    ------------------------------------------
    SH4	(*)	use BT/BF

  Jump Great Equal

 -------------------------------------------------------------------------------
o	Jump Great Equal (Signed >=)

    x86	JGE		REL(8,16,32)
    -------------------------------------------
    Alpha	BGE		R.PREL(20)		(if Reg >= 0)
    -------------------------------------------
    PPC	BC		PREL(16)		[CRi.LT]:false
    -------------------------------------------
    MIPS	BGEZ		R.PREL(18)		(if Reg >= 0)
    -------------------------------------------
    SPARC	BGE		PREL(?)
    -------------------------------------------
    68K	BGE		PREL(8,16,32)
    -------------------------------------------
    z80	(*) Complex sequence
    ------------------------------------------
    HPPA	MOVB	>=	R1,R2,PREL(17)
        MOVIB	>=	R1,Imm5,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    ------------------------------------------
    JVM	IFGE		32	REL16	(Test Word on stack 0)
        IF_ICMPGE       32	REL16	(Compare 2 words)
    ------------------------------------------
    SH4	(*)	use BT/BF

  Jump Less Equal

 -------------------------------------------------------------------------------
o	Jump Less Equal (Signed <=)

    x86	JLE		REL(8,16,32)
    ---------------------------------------
    Alpha	BLE		R.PREL(20)		(if Reg <= 0)
    ---------------------------------------
    PPC	BC		PREL(16)		[CRi.GT]:false
    ---------------------------------------
    MIPS	BLEZ		R.PREL(18)		(if Reg <= 0)
    ---------------------------------------
    SPARC	BLE		PREL(?)
    ---------------------------------------
    68K	BLE		PREL(8,16,32)
    ---------------------------------------
    z80	(*) Complex sequence
    ------------------------------------------
    HPPA	MOVB	<=	R1,R2,PREL(17)
        MOVIB	<=	R1,Imm5,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    ------------------------------------------
    JVM	IFLE		32	REL16	(Test Word on stack 0)
        IF_ICMPLE       32	REL16	(Compare 2 words)
    ------------------------------------------
    SH4	(*)	use BT/BF

  Jump Less

 -------------------------------------------------------------------------------
o	Jump Less (Signed <)

    x86	JL		REL(8,16,32)
    ----------------------------------------
    Alpha	BLT		R.PREL(20)		(if Reg < 0)
    ----------------------------------------
    PPC	BC		PREL(16)		[CRi.LT]:true
    ----------------------------------------
    MIPS	BLTZ		R.PREL(18)		(if Reg < 0)
    ----------------------------------------
    SPARC	BL		PREL(?)
    ----------------------------------------
    68K	BLT		PREL(8,16,32)
    ----------------------------------------
    z80	(*) Complex sequence
    ------------------------------------------
    HPPA	MOVB	<	R1,R2,PREL(17)
        MOVIB	<	R1,Imm5,PREL(17)
    ------------------------------------------
    IA-64	BR.XX		PREL(25)
                R,PREL(25)
    ------------------------------------------
    JVM	IFLT		32	REL16	(Test Word on stack 0)
        IF_ICMPLT       32	REL16	(Compare 2 words)
    ------------------------------------------
    SH4	(*)	use BT/BF
 ------------------------------------------------------------------------------
 Note: Else we have Jump if Overflow, and some more exotic jumps.
       And JUMP if = 0, <> 0 this is good jump too.
       And also, constructions for create loops.

       Add full scheme of signed/unsigned operation (JUMPS).

In ARM archittecture:
    branchs are always conditional. So look at calls and return
sections for more info.


35.2.1.7. ВЫЗОВ И ВОЗВРАТ ИЗ ПОДПРОГРАММ, БЕЗУСЛОВНЫЕ ПЕРЕХОДЫ

  Call subroutine

Собственно основные варианты:

    Direct	 - когда смещение куда переходить описано в команде
    Indirect - когда абсолютный адресс куда переходить береться из регистра

и
    Адресс возврата записывается в stack (типично для CISC)
    Адресс возврата записывается в специальный Link register (типично для RISC)

Direct/Stack:

    Push(Instruction_Pointer)
    Instruction_Pointer = Instruction_Pointer + Relative_Offset

Indirect/Stack:

    Push(Instruction_Pointer)
    Instruction_Pointer = Source

Direct/Link register:

    Link_Register = Instruction_Pointer
    Instruction_Pointer = Instruction_Pointer + Relative_Offset

Например для SPARC:

    call	address

        jmpl	address, %o8	! Jump and Link

Indirect/Link register:

    Link_Register = Instruction_Pointer
    Instruction_Pointer = Source

 ------------------------------------------------------------------------------
o	Call Subroutine

    x86	CALL		REL(16,32)
    ----------------------------------------
    Alpha	BSR		PREL(20)
        JSR		RR			(full 64bit jump)
    ----------------------------------------
    PPC	(*) BL/BLA and then save Link Register.
    ----------------------------------------
    MIPS	(*) JAL/JALR and then save Link Register.
    ----------------------------------------
    SPARC	CALL		PREL(?)
    ----------------------------------------
    68K	BSR		PREL(16)
        JSR		R	ADDR(32)	(D-,A- regs)
    ----------------------------------------
    z80	CALL   [cc]	ADDR(16)
    ----------------------------------------
    HPPA	BL		REL(17),R		(and then save Link Reg)
        BLR		R,R
        BV		R(R)			(Branch Vectored)
    ------------------------------------------
    IA-64	BR.CALL		??
    -----------------------------------------
    MCS51	ACALL		ADDR(11)
        LCALL		ADDR(16)
    -----------------------------------------
    JVM	JSR		REL16
        JSR_W		REL32
    -----------------------------------------
    ARM	BLcc		label			(Branch and Link)
    -----------------------------------------
    SH4	BSR		label
        JSR		@R

  Return from subroutine

Соответсвенно есть два варианта для возврата:

    из стека (типично для CISC)
    из Link Register (типично для RISC)

Return (stack):

    Pop(Instuction_Pointer)

Return (Link Register)

    Instruction_Pointer = Link_Register

Часто на RISC - Return - это такой же Call, но в качестве назначения
выступает регистр равный 0.

Например SPARC:

    ret	=>	jmpl	%i7+8,%g0
    retl	=>	jmpl	%o8+8,%g0	! for leaf subroutines

 ------------------------------------------------------------------------------
o	Return from subroutine

    x86	RET					(xx - deleted frame)
    -----------------------------------------
    Alpha	RET		RR			(full 64bit ret)
    -----------------------------------------
    PPC	(*) Fetch from stack, and then BL/BLA
    -----------------------------------------
    MIPS	(*) Fetch from stack, and then JR
    -----------------------------------------
    SPARC	????
    -----------------------------------------
    68K	RTS
    -----------------------------------------
    z80	RET   [cc]
    -----------------------------------------
    HPPA	(*) Fetch from stack, then BLR
    ------------------------------------------
    IA-64	BR.RET		???
    -----------------------------------------
    MCS51	RET
    -----------------------------------------
    JVM	RET		FRAME_PTR
        RET_W		FRAME_PTR
        IRETURN		(Return from function integer)
        LRETURN		(long)
        FRETURN         (float)
        DRETURN         (double)
        ARETURN         (object)
        RETURN          (null)
    ------------------------------------------
    ARM	(*) ???
    ------------------------------------------
    Sh4	RTS

  Unconditional Jump

Безусловные переходы тоже бывают Direct и Indirect

Direct:

    Instruction_Pointer = Instruction_Pointer + Relative_Offset

Indirect:

    Instruction_Pointer = Link_Register

Например для SPARC безусловный переход это тот-же уже хорошо знакомый нам
Jump and Link, только в качестве получателя используется регистр всегда
равный нулю.

    jmp	address

        jmpl	address,%g0

Часто RISC процессоры имеют особую форму инструкции безусловного перехода
с большим количеством битов под Offset.
Например если 32-разрядный RISC процессор имеет инсрукцию у которой 30-бит
выделено на offset, то он одной командой перехода может достичь любого места
памяти (так как типичные RISC команды имеют размер 32-бита и выровнены по
адрессу кратному 4 байтам).

 ------------------------------------------------------------------------------
o	Unconditional JUMP

    x86	JMP		REL(8,16,32)
    -------------------------------------
    Alpha	BR		PREL(20)	(different prediction logic)
        JMP		RR		(full 64-bit)
    -------------------------------------
    PPC	B		PREL(26)	(relative)
        BL		PREL(26)	(branch to Link register)
        BA		ADDR(26)	(absolute)
        BLA		ADDR(26)	(absolute to Link Register)
    -------------------------------------
    MIPS	J		PADDR(28)
        JR		R		(register)
        JAL		PADDR(28)	(Jump and Link)
        JALR		RR		(Jump and Link register)
    -------------------------------------
    SPARC	B		PREL(?)
        JMPL		PREL(?)R	(Jump and Link)
    -------------------------------------
    68K	BRA		PREL(16)
        JMP		R	ADDR(32)	(D-,A- regs)
    -------------------------------------
    z80	JR		PREL(8)
        JP		ADDR(16)	A
    -------------------------------------
    HPPA	(*)  conditional jump with ALWAYS flag and zero reg.
    ------------------------------------------
    IA-64	BR.XXX
        MOV		R1 = B1		(Move Branch Register)
                B1 = R1
    ---------------------------------------
    MCS51	AJMP		ADDR(11)
        LJMP		ADDR(16)
        SJMP		REL(8)
        JMP		@A+DPTR
    ---------------------------------------
    JVM	GOTO		REL16
        GOTO_2		REL32
    ---------------------------------------
    ARM	Bcc		label		(Branch)
    ---------------------------------------
    SH4	BRA		lable
        JMP		@R
 ------------------------------------------------------------------------------

Note: More operations:
        PUSH to stack
        POP  from stack.
        And general stack frame operations.


35.2.1.8. УСЛОВНЫЕ ПЕРЕСЫЛКИ И УСТАНОВКИ

  Conditional Move

    if (Condition)
    {
        Destination = Source
    }

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

 -------------------------------------------------------------------------------
o	Conditional MOVE

    x86	CMOVxx		RR	RI?
    ---------------------------------------
    Alpha	CMOVEQ	64	RRR	RRI
        CMOVGE	64	RRR	RRI
        CMOVGT	64	RRR	RRI
        CMOVLBC	64	RRR	RRI
        CMOVLBS	64	RRR	RRI
        CMOVLE	64	RRR	RRI
        CMOVLT	64	RRR	RRI
        CMOVNE	64	RRR	RRI
    ----------------------------------------
    PPC
    ----------------------------------------
    MIPS	MOVN	32/64	RRR			(!=0)
        MOVZ	32/64	RRR			(=0)
    ----------------------------------------
    SPARC	MOVA	max	RRR	RRI
        MOVN	max	RRR	RRI
        MOVNE	max	RRR	RRI
        MOVE	max	RRR	RRI
        MOVG	max	RRR	RRI
        MOVGE	max	RRR	RRI
        MOVLE	max	RRR	RRI
        MOVL	max	RRR	RRI
        MOVGU	max	RRR	RRI
        MOVLEU	max	RRR	RRI
        MOVPOS	max	RRR	RRI
        MOVNEG	max	RRR	RRI
        MOVVC	max	RRR	RRI
        MOVVS	max	RRR	RRI
    -----------------------------------------

                V9
    ----------------------------------------
    68K
    ----------------------------------------
    z80
    ----------------------------------------
    ARM	MOVcc	32	RR
                RI

  Conditional Set

 -------------------------------------------------------------------------------
o	Conditional SET

    x86	SETxx		R
    ----------------------------------------
    Alpha
    ----------------------------------------
    PPC
    ----------------------------------------
    MIPS	STL		RRR			(set if Less:Signed)
        STLI		RRI			(Signed Immediate)
        SLTIU		RRI			(Unsigned)
        SLTU		RRR
    ----------------------------------------
    SPARC	(*) via conditional moves
    ----------------------------------------
    68K	Sxx		R			(A-,D- regs)
    ----------------------------------------
    z80
 -------------------------------------------------------------------------------


35.2.1.9. ОПЕРАЦИИ С БИТАМИ И БИТОВЫМИ СТРОКАМИ

    (Need to Update This sections)

  Insert Bitstring

PPC:

IA-64:
    dep	r1 = r2,r3,pos{6},len{4}

x86:
С помощью команд SHLD, SHRD

 -----------------------------------------------------------------------------
o	Insert (Deposite) Data into Bitstring

    IA-64	DEP	64	R1=R2,R3,pos(6),len(4)
            64	R1=I1,R3,pos(6),len(4)
        DEP.Z	64	R1=R2,pos(6),len(4)	Zero form
            64	R1=I8,pos(6),len(6)
        ----- ----- ----- ------
        MIX1.1	64	R1=R2,R3		Mix Integer Bytes
        MIX2.1	64	R1=R2,R3
        MIX4.1	64	R1=R2,R3
        ----- ----- ----- ----
        MUX1	64	R1=R2,mbtype(4)		One byte form
        MUX2	64	R1=R2,mhtype(8)		two byte form
    ----------------------------------------
    x86	(*)  Use SHLD, SHRD for deposite strings
    ----------------------------------------
    68K	BFINS	32	R,M,pos,len

  Extract Bitstring

IA-64:
extr
extr.u

 -----------------------------------------------------------------------------
o	Extract Data from Bitstring

    IA-64	EXTR	64	R1=R2,pos(6),len(6)	(Signed)
        RXTR.U	64	R1=R2,pos(6),len(6)	(Unsigned)
    -----------------------------------------
    x86	(*)  Use SHLD, SHRD for deposite strings
    -----------------------------------------
    68K	BFEXTRS	32	R,pos,len,M
        BFEXTRU	32	R,pos,len,M

  Bit Test/Set/Clear

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

Поэтому например если мы хотим на SPARC узнать значение скажем бита 2 в R5:
то

    btst	2,%r5

        andcc	%r5,4,%g0	! в ZF мы получим инверсию этого бита

Или если мы хотим узнать его значение, а потом установить то:

                    ! сначало тестируем
        andcc	%r5,4,%g0	! ставить ZF

    bset	2,%r5                   ! псевдооперация
                    ! означает:

        or	%r5,4,%r5	! не трогает флаги

Если мы хотим его сбросить

    bclr	2,%r5

        andn	%r5,4,%r5

А если мы хотим поменять его значение, то

    btog	2,%r5

        xor	%r5,4,%r5

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

  Bit Test

    CF = BIT[Source, Number]

 -----------------------------------------------------------------------------
o	Bit Test

    X86	BT	16,32	RR      		CF <- Bit
                RI
    -----------------------------------------
    Z80	BIT	8	_I_R
    -----------------------------------------
    68K	BTST	8,32	RR
                RI
    -----------------------------------------
    IA64	TBITxx	64	PPRI

  Bit Set

    BIT[Source, Number] = 1

 -----------------------------------------------------------------------------
o	Bit Set

    X86	BTS	16,32	RR
                RI
    -----------------------------------------
    Z80	SET	8	_I_R
    -----------------------------------------
    68K	BSET	8,32	RR
                             RI

  Bit Reset

    BIT[Source, Number] = 0

 -----------------------------------------------------------------------------
o	Bit Reset

    X86	BTR	16,32	RR
                RI
    -----------------------------------------
    Z80	RES	8	_I_R
    -----------------------------------------
    68K	BCLR	8,32	RR
                RI

  Bit Complement

    BIT[Source, Number] = - BIT[Source, Number]

 -----------------------------------------------------------------------------
o	Bit Complement

    X86	BTC	16,32	RR
                RI
    -----------------------------------------
    68K	BCHG	8,32	RR
                RI
 -------------------------------------------------------------------------

  Population Count

    Destionation = Number_of_1s_Bits(Source)

PowerPC:
Существует инструкция POPCNTB которая вычисляет population count
в каждом байте.
Для вычисления population count в двойном слове:

    popcntb	RT,RA
    mulld	RT,RT,RB      # RB = 0x0101010101010101
    srdi	RT,RT,56      # now RT = popilation count

Для SPARC - c помощью population count - можно реализовать number of trailing zeroes

    int ffs(unsigned zz) { return popc(zz ^ (~ (-zz))) }

    neg	%IN, %M_IN
    xnor	%IN, %M_IN, %TEMP
    popc	%TEMP, %RESULT
    movrz	%IN, %g0, %RESULT	! Result must be 0 if %IN ==

 ---------------------------------------------------------------------------
o       Population count

    x86	POPCNT	16	RR	RM		SSE 4.2
            32	RR	RM
    ------------------------------------
    Alpha	CTPOP
    ------------------------------------
    PPC	POPCNTB	'*'	RR
        (*) Complex Sequence
    ------------------------------------
    MIPS
    ------------------------------------
    SPARC	POPC	max	RR	RI
    ------------------------------------
    HPPA
    ------------------------------------
    68K
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64   POPCNT	max	RR
    ------------------------------------
    SH4

  Count of Leading Zeroes

    Destinaton = Position_of_First_Leftmost_Bit_which_is_1(Source)

VAX-11:
    FFC	off,len,addr,long		Find first clear bit
    FFS	off,len,addr,long		Find first set bit

IA-64
    czx1.l	r1=r2		Compute Index of first Zero Element (Byte,word)  Left
    czx1.r	r1=r2								 Right

 ---------------------------------------------------------------------------
o	Count Number of Leading Zeroes

    x86	BSR	16	RR	RM
            32	RR	RM
    ------------------------------------
    Alpha	CTLZ
    ------------------------------------
    PPC	CNTLZW	max     RR
        CNTLZW. max	RR
    ------------------------------------
    MIPS
    ------------------------------------
    SPARC
    ------------------------------------
    HPPA
    ------------------------------------
    68K	BFFO	32	RRII	RRII	позволяет искать биты в битовом поле
                        68020+
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4

  Count of Trailing Zeroes

    Destinaton = Position_of_First_Rightmost_Bit_which_is_1(Source)

 ---------------------------------------------------------------------------
o	Count Number of Trailing Zeroes

    x86	BSF	16	RR	RM
            32	RR	RM
    ------------------------------------
    Alpha	CTTZ
    ------------------------------------
    PPC	CNTLZD	max	RR
    ------------------------------------
    MIPS
    ------------------------------------
    SPARC
    ------------------------------------
    HPPA
    ------------------------------------
    68K
    ------------------------------------
    VAX-11
    ------------------------------------
    ARM
    ------------------------------------
    IA-64
    ------------------------------------
    SH4


35.2.1.10 ОПЕРАЦИИ СО СТЕКОМ

  Push to stack

    Memory[Automodified_EA] = Source

Как правило в CISC процессорах данные команды часто являются выделенными
(кроме того адресса возврата при вызове подпрограмм тоже ложаться в этот стек).

Например x86:

    PUSH	source

        ESP = ESP - 4	  ; Stack pointer register
        MOV	[ESP], source

    POP	destination

        MOV	destination,[ESP]
        ESP = ESP + 4

Для RISC машин это самые обычные команды загрузки/выгрузки связанные с памятью,
только используется автоинкрементальная/автодекрементальная форма для EA.

Например 68K (оно не RISC, но принцип тот-же):

    add	(a4)+,d0	// A4 = A4 + 4  after memory access
    mov	d2,-(a4)	// A4 = A4 - 4  before memory access

Часто  режим обновления задается мнемоникой, например PPC:

    ld	r2,4(r3)	// обыная загрузка
    ldu	r2,4(r3)	// загрузка с обновлением регистра r3
                // после операции
                // r3 = r3 + ((sign_ext(4)) << 2)

    std	r2,4(r3)	// просто запись
    stdu	r2,4(r3)	// обновление r3, потом запись

Заметим, что для PPC - Load обновляет базовы регистр для EA - после,
а Store - до (реально просто запись идет по новому EA, а обновление
происходит паралельно, то есть если сделать:

    stdu	r2,2(r2)

то в память будет записано старое значение r2 (до обновления).

Некоторые прхитектуры поддерживают как pre-, так post-обновление и это
кодируется в команде.

Собственно для архитектур в которых stack pointer не забит жестко аппаратно
какой регистр будет служить stack pointer определяется соглашениями по
runtime (ABI = Application Binary Interface) для конкретной платформы.

 ---------------------------------------------------------------------------
o	Push to Stack

    X86	PUSH	(8)/16/32	R
                    M
                    I
    ---------------------------------------
    Z80	PUSH	16		R
    ---------------------------------------
    ARM	STMcc	32		RR

  Pop from stack

    Destination = Memory[Automodified_EA]

Читайте комментарии для push.

 ---------------------------------------------------------------------------
o	Pop from Stack

    X86    	POP	16/32		R
                    M
    ---------------------------------------
    Z80	POP	16		R
    ---------------------------------------
    ARM	LDMcc	32		RR
 ---------------------------------------------------------------------------
Note: so, we also may describe TRAPs, conditional TRAPs and
      stack framing operations, Rotates.

      That also additional CPUs we must to add:
    o	Zilog Z8000


35.2.2. FP КОММАНДЫ

Of course, all register are Floating-point :)

  FP Addition

    destination = source1 + source2

 -------------------------------------------------------------------------------
o	F.P	Addition

    x86	FADD		AR	RA
    ----------------------------------------
    Alpha	ADDF		RRR		(F-floating)
        ADDG		RRR		(G-floating)
        ADDS		RRR		(S-floating)
        ADDT		RRR		(T-floating)
    ----------------------------------------
    MIPS	ADD.S	32	RRR
        ADD.D	64	RRR
    -----------------------------------------
    SPARC	FADDS		RRR
        FADDD		RRR
        FADDQ		RRR
    -----------------------------------------
    PPC	FADDS	32	RRR
        FADD	64	RRR
    -----------------------------------------
    HPPA	FADDxx		RRR
    -----------------------------------------
    IA-64	FADD.pc.sf	F1=F2,F3	(Pop: fma.pc.sf F1=F3,f1,F2)
    (Single)    .s  .s0
    (Double)    .d	.s1
            .s2
            .s3 (Status Flags accessed)
    ------------------------------------------
    68K	FADD.S		[EA],FPn	(Default rounding)
        FADD.D		[EA],FPn
        FADD.X		[EA],FPn
                FPm,FPn
        FrADD.f		[EA],FPn	(Specific Rounding)
        FrADD.X		FPm,FPn
         S    	(round to single)
         D	(round to double)
    -------------------------------------------
    JVM	FADD	32
        DADD	64

  FP Subtract

    destination = source1 - source2

 -------------------------------------------------------------------------------
o	F.P.	Subtraction

    x86	FSUB		AR	RA
        FSUBR		AR	RA	(reverse operands)
    -----------------------------------------
    Alpha	SUBF		RRR		(F-floating)
        SUBG		RRR		(G-floating)
        SUBS		RRR		(S-floating)
        SUBT		RRR		(T-floating)
    -----------------------------------------
    MIPS	SUB.S		RRR
        SUB.D		RRR
    -----------------------------------------
    SPARC	FSUBS		RRR
        FSUBD		RRR
        FSUBQ		RRR
    -----------------------------------------
    PPC	FSUB	64	RRR
        FSUBS	32	RRR
    -----------------------------------------
    HPPA	FSUBxx		RRR
    -----------------------------------------
    IA-64	FSUB.pc.sf	F1=F3,F2	(pop: fms.pc.sf F1=F3,f1,F2)
    ------------------------------------------
    68K	FSUB.S		[EA],FPn	(Default rounding)
        FSUB.D		[EA],FPn
        FSUB.X		[EA],FPn
                FPm,FPn
        FrSUB.f		[EA],FPn	(Specific Rounding)
        FrSUB.X		FPm,FPn
         S    	(round to single)
         D	(round to double)
    -------------------------------------------
    JVM	FSUB	32
        DSUB	64

  FP Multiply

    destination = source1 * source2

 -------------------------------------------------------------------------------
o	F.P.   Multiply

    x86	FMUL		AR	RA
    -----------------------------------------
    Alpha	MULF		RRR		(F-floating)
        MULG		RRR		(G-floating)
        MULS		RRR		(S-floating)
        MULT		RRR		(T-floating)
    -----------------------------------------
    MIPS	MUL.S		RRR
        MUL.D		RRR
    -----------------------------------------
    SPARC	FMULS		RRR
        FMULD		RRR
        FMULQ		RRR
    -----------------------------------------
    PPC	FMUL	64	RRR
        FMULS	32	RRR
    -----------------------------------------
    HPPA	FMPYxx		RRR
        XMPYUxx		RRR	(Fixed Point Unsigned Multiply)
    -----------------------------------------
    IA-64	FMPY.pc.sf	F1=F3,F4	(pop:fma.pc.sf F1=F3,F4,f0)
    ------------------------------------------
    68K	FMUL.S		[EA],FPn	(Default rounding)
        FMUL.D		[EA],FPn
        FMUL.X		[EA],FPn
                FPm,FPn
        FrMUL.f		[EA],FPn	(Specific Rounding)
        FrMUL.X		FPm,FPn
         S    	(round to single)
         D	(round to double)
        FSGLMUL.F	[EA],FPn	(Single Precension)
        FSGLMUL.X	FPm,FPn
    -------------------------------------------
    JVM	FMUL	32
        DMUL	64

  FP Divide

    destination = source1 / source2

 -------------------------------------------------------------------------------
o	F.P.	Divide

    x86	FDIV		AR	RA
        FDIVR		AR	RA	(reverse operands)
    -----------------------------------------
    Alpha	DIVF		RRR		(F-floating)
        DIVG		RRR		(G-floating)
        DIVS		RRR		(S-floating)
        DIVT		RRR		(T-floating)
    -----------------------------------------
    MIPS	DIV.S		RRR		(S)
        DIV.D		RRR		(D)
    -----------------------------------------
    SPARC	FDIVS		RRR
        FDIVD		RRR
        FDIVQ		RRR
    -----------------------------------------
    PPC	FDIV	64	RRR
        FDIVS	32	RRR
    -----------------------------------------
    HPPA	FDIV		RRR
    ------------------------------------------
    68K	FDIV.S		[EA],FPn	(Default rounding)
        FDIV.D		[EA],FPn
        FDIV.X		[EA],FPn
                FPm,FPn
        FrDIV.f		[EA],FPn	(Specific Rounding)
        FrDIV.X		FPm,FPn
         S    	(round to single)
         D	(round to double)
        FSGLDIV.F	[EA],FPn	(Single Precension)
        FSGLDIV.X	FPm,FPn
    -------------------------------------------
    JVM	FDIV	32
        DDIV	64

  FP Remainder

    destination = source1 % source2

 -------------------------------------------------------------------------------
o	F.P.	Remainder

    x86	FPREM		AF
    -----------------------------------------
    Alpha	(*) Complex sequence
    -----------------------------------------
    MIPS	(*) Complex sequence
    -----------------------------------------
    SPARC	(*) Complex sequence
    -----------------------------------------
    PPC	(*) Complex sequence
    -------------------------------------------
    JVM	FEM	32
        DREM	64

  FP Absolute Value

Absolute value:

    destination = |source|

Negative absolute value:

    destination = - |source|

 -------------------------------------------------------------------------------
o	F.P.	Absolute Value

    x86	FABS		A
    -----------------------------------------
    Alpha	CPYS		RRR	(Copy Sign) (from positive number f31)
    -----------------------------------------
    MIPS	ABS.S	32	RR
        ABS.D	64	RR
    -----------------------------------------
    SPARC	FABSS		RR
        FABSD		RR		V9
        FABSQ		RR		V9
    -----------------------------------------
    PPC	FABS		RR
    -----------------------------------------
    HPPA	FABSxx		RR
    -----------------------------------------
    IA-64	FABS	64	F1=F2		(Pop: fmerge.s F1=f0,F2)
    ------------------------------------------
    68K	FABS.S		[EA],FPn	(Default rounding)
        FABS.D		[EA],FPn
        FABS.X		[EA],FPn
                FPm,FPn
                FPn
        FrABS.f		[EA],FPn	(Specific Rounding)
        FrABS.X		FPm,FPn
        FrABS.X		FPn
         S    	(round to single)
         D	(round to double)
    -----------------------------------------
    JVM	(*) Complex Sequence

  FP Negate

    destination = -source

 -------------------------------------------------------------------------------
o	F.P.    Negate (Change sign)

    x86	FCHS		A
    -----------------------------------------
    Alpha	CPYSN		RRR	(Copy Sign Negative, all 3 registers
                    is same)
    -----------------------------------------
    MIPS	NEG.S		RR
        NEG.D		RR
    -----------------------------------------
    SPARC	FNEGS		RR
        FNEGD		RR		V9
        FNEGQ		RR		V9
    -----------------------------------------
    PPC	FNEG		RR
    -----------------------------------------
    IA-64	FNEG		F1=F3		(Pop: fmerge.ns F1=F3,F3)
    ------------------------------------------
    68K	FNEG.S		[EA],FPn	(Default rounding)
        FNEG.D		[EA],FPn
        FNEG.X		[EA],FPn
                FPm,FPn
                FPn
        FrNEG.f		[EA],FPn	(Specific Rounding)
        FrNEG.X		FPm,FPn
        FrNEG.X		FPn
         S    	(round to single)
         D	(round to double)
    ------------------------------------------
    JVM	FNEG	32
        DNEG	64

  FP Square Root

                        ________
               /
    destination = V  source

 -------------------------------------------------------------------------------
o	F.P.  	Square Root

    x86	FSQRT		A
    -----------------------------------------
    Alpha   (*) Complex sequence
    -----------------------------------------
    MIPS	SQRT.S		RR
        SQRT.D		RR
    -----------------------------------------
    SPARC	FSQRTS		RR
        FSQRTD		RR
        FSQRTQ		RR
    -----------------------------------------
    PPC	FSQRT	64	RR
        FSQRTS	32	RR
    -----------------------------------------
    HPPA	FSQRTxx		RR
    -----------------------------------------
    IA-64	(*) Complex Algorithm based on
        FRSQRTA.sf	F1,P2=F3 (Reciprocal Square Root Approximation)
    -----------------------------------------
    68K	FSQRT.S		[EA],FPn	(Default rounding)
        FSQRT.D		[EA],FPn
        FSQRT.X		[EA],FPn
                FPm,FPn
                FPn
        FrSQRT.f	[EA],FPn	(Specific Rounding)
        FrSQRT.X	FPm,FPn
        FrSQRT.X	FPn
         S    	(round to single)
         D	(round to double)
 -------------------------------------------------------------------------------

  FP Multiply-Add/Multiply-Subtract

Multiply Add:

    destination = (source1 * source2) + source3

Multiply Subtract:

    destination = (source1 * source2) - source3

Negative Multiply Add:

    destination = - [(source1 * source2) + source3]

Negative Multiply Subtract

    destination = - [(source1 * source2) - source3]

 -------------------------------------------------------------------------------
o	F.P. Multiply/Add joined operation

    x86
    -----------------------------------------
    Alpha
    -----------------------------------------
    MIPS	MADD.S		RRRR			(addition)
        MADD.D		RRRR			d <- (a*b)+c
        MSUB.S		RRRR			(subtraction)
        MSUB.D		RRRR			d <- (A*b)-c
        NMADD.S		RRRR			(all MIPS IV)
        NMADD.D		RRRR			d <- -(a*b+c)
        NMSUB.S		RRRR
        NMSUB.D		RRRR			d <- -(a*b-c)
    -----------------------------------------
    PPC	FMADD	64	RRRR			d <- (a*b) + c
        FMADDS	32	RRRR
        FMSUB	64	RRRR			d <- (a*b) - c
        FMSUBS	32	RRRR
        FNMADD	64	RRRR			d <- -(a*b+c)
        FNMADDS	32	RRRR
        FNMSUB	64	RRRR			d <- -(a*b-c)
        FNMSUBS	32	RRRR
    -----------------------------------------
    SPARC	(??)
    -----------------------------------------
    HPPA	FMPYADD		RRRRR		c <- (a * b); e <- (e + a);
        FMPYSUB		RRRRR		c <- (a * b); e <- (e - a);
    -----------------------------------------
    IA-64	FMA.pc.sf	F1=F3,F4,F2		Multiply Add
        FMS.pc.sf	F1=F3,F4,F2		Multiply Subtract

  FP Maximum/Minimum/Absolute Maximum/Absolute Maximum

    destination = (source1 > source2): source1 : source2

    destination = (source1 < source2): source1 : source2

    destination = (|source1| < |source2|) source1 : source2

    destination = (|source1| > |source2|) source1 : source2

THIS SECTION IS UNDER CONSTRUCTION

  FP Move

 -------------------------------------------------------------------------------
o	Move	F.P. regsiter

    x86	(*) Complex sequence
    -----------------------------------------
    Alpha	FCPYSE		RRR		(the last two register is
                         same)
    -----------------------------------------
    MIPS	MOV.S		RR
        MOV.D		RR
    -----------------------------------------
    SPARC	FMOVS		RR
        FMOVD		RR		V9
        FMOVQ		RR		V9
    -----------------------------------------
    PPC	FMR		RR
    -----------------------------------------
    HPPA	FCPYxx		RR
    -----------------------------------------
    IA-64	MOV		F1=F3	(Pop: fmerge.s F1=F3,F3)

 -------------------------------------------------------------------------------
o	F.P.	Extract Exponent and Significand

    x86	FXTRACT		AF
    -----------------------------------------
    Alpha	FCPYSE		RRR		(copy sign and exponent from
                        two different registers)
    -----------------------------------------
    MIPS
    -----------------------------------------
    PPC
    -----------------------------------------
    IA-64	GETF.S		R1=F1		(Single form)
            .D		R1=F1		(Double form)
            .EXP	R1=F1		(Exponent form)
            .SIG	R1=F1		(Significand form)
        (back operation is:)
        SETF.S/D/EXP/SIG F1=R1
 -------------------------------------------------------------------------------
o	F.P.	Scale	x=x*2^y

    x86	FSCALE		AF
    -----------------------------------------
    Alpha
    -----------------------------------------
    MIPS
    -----------------------------------------
    PPC

 -------------------------------------------------------------------------------
o	Exhange F.P registers

    x86	FXCH		AR
    -----------------------------------------
    Alpha
    -----------------------------------------
    MIPS
    -----------------------------------------
    PPC

  FP Load

 -------------------------------------------------------------------------------
o	Load Single-precension (32-bit) F.P

    x86	FLD		AM
    -----------------------------------------
    Alpha	LDF		R[RA+Disp]		(F-,VAX-format)
        LDS		R[RA+Disp]		(S-,IEEE-format)
    -----------------------------------------
    MIPS	LWC1	32	R[R+Disp]
        LWXC1	32	R[Ra+Ridx]
    -----------------------------------------
    SPARC	LDF	32?	R[Ra+Ra/Disp]
    -----------------------------------------
    PPC	LFS		R[RA+Disp]
        LFSU		R[RA+Disp]		(update Address)
        LFSUX		R[Ra+Ridx]		(update address)
        LFSX		R[Ra+Ridx]
    -----------------------------------------
    HPPA	FLDWXxx		R(scaleR)R		(indexed)
        FLDWSxx		R(RDisp5)R		(short)
    ------------------------------------------
    IA-64	LDFS.fldtype.ldhint	F1 = [R3]	(no base update)
        LDFS.fldtype.ldhint	F1 = [R3],R2	(base update)
        LDFS.fldtype.ldhint 	F1 = [R3],I9	(imm base update)
                            (PAIR)
        LDFPS.fldtype.ldhint	F1,F2 = [R3]	(no base update)
                    F1,F2 = [R3], 8 (base update)
    ------------------------------------------
    68K	FMOVE.S		[EA],FPn
    ------------------------------------------
    JVM	FALOAD				(Array)
        FLOAD_0
        FLOAD_1
        FLOAD_2
        FLOAD_3
        FLOAD		FRAME_PTR
 -------------------------------------------------------------------------------
o	Load Doble-precension (64-bit) F.P.

    x86	FLD		AM
    -----------------------------------------
    Alpha	LDG		R[RA+Disp]		(G-,VAX-format)
        LDT		R[RA+Disp]		(T-,IEEE-format)
    -----------------------------------------
    MIPS	LDC1	64	R[R+Disp]
        LDXC1	64	R[Ra+Ridx]
    -----------------------------------------
    SPARC	LDDF	64?	R[Ra+Ra/Disp]
    -----------------------------------------
    PPC	LFD		R[RA+Disp]
        LFDU		R[RA+Disp]		(update Address)
        LFDUX		R[Ra+Ridx]		(update address)
        LFDX		R[Ra+Ridx]
    -----------------------------------------
    HPPA	FLDDXxx		R(scaleR)R
        FLDDSxx		R(RDisp5)R		(short)
    ------------------------------------------
    IA-64	LDFD.fldtype.ldhint	F1 = [R3]	(no base update)
        LDFD.fldtype.ldhint	F1 = [R3],R2	(base update)
        LDFD.fldtype.ldhint 	F1 = [R3],I9	(imm base update)
                            (PAIR)
        LDFPD.fldtype.ldhint	F1,F2 = [R3]	(no base update)
                    F1,F2 = [R3], 16 (base update)
    ------------------------------------------
    68K	FMOVE.D		[EA],FPn
    ------------------------------------------
    JVM	DALOAD				(Array)
        DLOAD_0
        DLOAD_1
        DLOAD_2
        DLOAD_3
        DLOAD		FRAME_PTR
 -------------------------------------------------------------------------------
o	Load Extended-precension F.P.

    x86	FLD		AM			(80-bit)
    -----------------------------------------
    Alpha
    -----------------------------------------
    MIPS
    -----------------------------------------
    SPARC	LDQF	?	R[Ra+Ra/Disp]
    -----------------------------------------
    PPC
    ------------------------------------------
    IA-64	LDFE.fldtype.ldhint	F1 = [R3]	(no base update)
        LDFE.fldtype.ldhint	F1 = [R3],R2	(base update)
        LDFE.fldtype.ldhint 	F1 = [R3],I9	(imm base update)
    ------------------------------------------
    68K	FMOVE.X		[EA],FPn

  FP Store

 -------------------------------------------------------------------------------
o	Store Single-precension (32-bit) F.P

    x86	FST		AM
    -----------------------------------------
    Alpha	STF		R[RA+Disp]		(F-,VAX-format)
        STS		R[RA+Disp]		(S-,IEEE-format)
    -----------------------------------------
    MIPS	SWC1		R[RA+Disp]
        SWXC1		R[Ra+Disp]
    -----------------------------------------
    SPARC	STF	?	R[Ra+Ra/Disp]
    -----------------------------------------
    PPC	STFS		R[RA+Disp]
        STFSU		R[RA+Disp]		(update Address)
        STFSUX		R[Ra+Ridx]		(update address)
        STFSX		R[Ra+Ridx]
    -----------------------------------------
    HPPA	FSTWXxx		RR(scaleR)
        FSTWSxx		R(RDisp5)R		(short)
    -----------------------------------------
    IA-64	STFS.sthint	[R3] = F2		(no-update base)
                [R3] = F2, I9		(update base)
    ------------------------------------------
    68K	FMOVE.S		FPn,[EA]
    ------------------------------------------
    JVM	FASTORE				(Array)
        FSTORE_0
        FSTORE_1
        FSTORE_2
        FSTORE_3
        FSTORE		VAR_IDX
 -------------------------------------------------------------------------------
o	Store Doble-precension (64-bit) F.P.

    x86	FST		AM
    -----------------------------------------
    Alpha	STG		R[RA+Disp]		(G-,VAX-format)
        STT		R[RA+Disp]		(T-,IEEE-format)
    -----------------------------------------
    MIPS	SDC1		R[Ra+Disp]
        SDXC1		R[Ra+Ridx]
    -----------------------------------------
    SPARC	STDF	?	R[Ra+Ra/Disp]
    -----------------------------------------
    PPC	STFD		R[RA+Disp]
        STFDU		R[RA+Disp]		(update Address)
        STFDUX		R[Ra+Ridx]		(update address)
        STFDX		R[Ra+Ridx]
    -----------------------------------------
    HPPA	FSTDXxx		RR(scaleR)		(indexed)
        FSTDSxx		R(RDisp5)R		(short)
    -----------------------------------------
    IA-64	STFD.sthint	[R3] = F2		(no-update base)
                [R3] = F2, I9		(update base)
    ------------------------------------------
    68K	FMOVE.D		FPn,[EA]
    ------------------------------------------
    JVM	DASTORE					(Array)
        DSTORE_0
        DSTORE_1
        DSTORE_2
        DSTORE_3
        DSTORE		VAR_IDX
 ------------------------------------------------------------------------------
o	Store Extended-precension F.P.

    x86	FST		AM			(80-bit)
    -----------------------------------------
    Alpha
    -----------------------------------------
    MIPS
    -----------------------------------------
    SPARC	STQF	?	R[Ra+Ra/Disp]
    -----------------------------------------
    PPC
    -----------------------------------------
    IA-64	STFE.sthint	[R3] = F2		(no-update base)
                [R3] = F2, I9		(update base)
    ------------------------------------------
    68K	FMOVE.X		FPn,[EA]

  Convert between FP Formats

 -------------------------------------------------------------------------------
o	Convert between F.P. formats

    x86	(*) Throught FLD/FST
    -----------------------------------------
    Alpha	CVTDG		RR			(F -> G)
        CVTGD		RR			(G -> D)
        CVTGF		RR			(G -> F)
        CVTTS		RR			(T -> S)
    -----------------------------------------
    MIPS	CVT.D.S		RR			(S -> D)
        CVT.S.D		RR			(D -> S)
    -----------------------------------------
    SPARC	FSTOD		RR			(S -> D)
        FSTOQ		RR			(S -> Q)
        FDTOS		RR			(D -> S)
        FDTOQ		RR			(D -> Q)
        FQTOD		RR			(Q -> D)
        FQTOS		RR			(Q -> S)
    -----------------------------------------
    PPC	FRSP		RR			(to single)
    ------------------------------------------
    HPPA	FCNVFFxx	RR			(S->D,D->S)
    ------------------------------------------
    JVM	F2D					(F->D)
        D2F					(D->F)

  FP Branch/Compare

Условия для блоков с плавающей точкой

Для старых архитектур (особенно CISC) характерно, что
блок с плавающей точкой был встроен в сопроцессор, поэтому
как правило отсутсвуют непосредственные переходы по
условиям с плавающей точкой. Что бы их реализовать надо
загрузить слово состояния FP из сопроцессора в процессор,
а потом его анализировать.

Типичный пример:

x86:
    fnstsw	ax	; читаем FP. SW в AX
    sahf		; записываем AX в регистр флагов
            ; готовы делать переходы по FP

MIPS:	C.cond.S
    C.cond.D

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

x86:	fcomi	st,st(2)	; например

x86:	FCOMIxx			ZF	PF	CF
    ST(0) > ST(i)		0	0	0
    ST(0) < ST(i)		0	0	1
    ST(0) = ST(i)		1	0	0
    unordered		1	1	1

Ясно что FP числа - это всегда signed, но зато в случае сравнения
могут получиться новое условие

    Unoredered

Это когда сравнить нельзя. Например что больше +infinity или +infinity?
Или если сравнивать NaN с числом

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

    - Invalid Operand (NaN)
    - Overflow
    - Underflow

 -------------------------------------------------------------------------------
o	F.P. Branch/Compare

    x86	FCOMI		AR		(set integer flags)
    -----------------------------------------
    Alpha	FBEQ		R.PREL(20)	(== 0)
        FBNE		R.PREL(20)	(!= 0)
        FBGT		R.PREL(20)	(>  0)
        FBLE		R.PREL(20)	(<= 0)
        FBLT		R.PREL(20)	(< 0)
        FBGE		R.PREL(20)	(>= 0)
    -----------------------------------------
    MIPS	C.cond.S  32	RR
        C.cond.D  64    RR
                conditions are:
                    Base	Inversed
                    F	T	False
                    UN	OR	Unordered
                    EQ	NEQ	Equal
                    OLT	UGE	Ordered or Less
                    ULT	OGE	Unordered or Less
                    OLE	UGT	Ordered <=
                    ULE	OGT	Unordered <=
                    NGLE	GLE	Not Greater (Less Equal)
                    SEQ	SNE	(Signaled) ==
                    NGL	GL	(Non Greater or Less))
                    LT	NLT	<
                    NGE	GE
                    LE	NLE
                    NGT	GT
        and then,
        BC1F		PREL(18)	(branch if condition false)
        BC1T		PREL(18)	(branch if condition true)
    -----------------------------------------
    SPARC	FCMPS		RR
        FCMPD		RR
        FCMPQ		RR
        and then
        FBG		PREL(?)
        FBUG		PREL(?)
        FBL		PREL(?)
        FBUL		PREL(?)
        FBLG		PREL(?)
        FBNE		PREL(?)
        FBE		PREL(?)
        FBUE		PREL(?)
        FBGE		PREL(?)
        FBUGE		PREL(?)
        FBLE		PREL(?)
        FBULE		PREL(?)
    -----------------------------------------
    PPC	FCMPO		ccRR		(Ordered compare)
        FCMPU		ccRR		(Unordered compare)
        and then see integer code for describe operations
    ------------------------------------------
    HPPA	FCMPxx		RR
        and then see integer code for descibe operations
        FTESTxx			(Check current condition (FP state)
                    if success, the next instruction will
                    be nullified.
    -------------------------------------------
    IA-64	FCMP.frel.fctype.sf	P1,P2=F1,F2	(Compare)
             eq	   .s0
             lt	  unc    .s1
             le          .s2
             gt
             ge
           unord
             neq  (no equal)
             nlt
             nle
             ngt
             ngt
             nge
             ord
    ------------------------------------------
    68k	FBcc		???
          cc = EQ,NE,OGT,ULE,OGE,ULT,OLT,UGE,OLE,UGT,OGL,UEQ,OR,UN,F,T)
    ------------------------------------------
    JVM	FCMPL	32		(less)
        FCMPG	32		(greater)
        DCMPL	32		(less)
        DCMPG	32		(greater)
 -------------------------------------------------------------------------------
o	F.P. Conditional Move

    x86	FCOMI		AR		(set integer flag)
        and then
        FCMOVB		AR
        FCMOVNE		AR
        FCMOVE		AR
        FCMOVNE		AR
        FCMOVBE		AR
        FCMOVNBE	AR
        FCMOVU		AR		(unordered)
        FCMOVNU		AR		(not unordered)
    -----------------------------------------
    Alpha	FCMOVEQ		RRR		(compare one operand with 0,
        FCMOVGE		RRR		and if condition true, do
        FCMOVGT		RRR		move second to third).
        FCMOVLE		RRR
        FCMOVLT		RRR
        FCMOVNE		RRR
    ------------------------------------------
    MIPS	see (F.P. branch)

        [MIPS IV have]
        MOVF
        MOVN
        MOVT
        MOVZ
    ------------------------------------------
    SPARC	(??)
    ------------------------------------------
    PPC

  Load predefined constant

 -------------------------------------------------------------------------------
o	Load special constant

    x86	FLDZ		A			(0)
        FLDL2T		A			(log2 10)
        FLDL2E		A			(log2 e)
        FLDPI		A			(pi)
        FLDLG2		A			(log10 2)
        FLDLN2		A			(loge  2)
        FLD1		A			(1)
    -----------------------------------------
    Alpha						R31 = 0
    -----------------------------------------
    MIPS
    -----------------------------------------
    PPC
    -----------------------------------------
    JVM	FCONST_0				(0)
        FCONST_1				(1)
        FCONST_2				(2)
        DCONST_0				(0)
        DCONST_1				(1)

  FP Load Integer

 -------------------------------------------------------------------------------
o	Load	Integer

    x86	FILD	16	AM
            32	AM
            64	AM
    -----------------------------------------
    Alpha	??
    -----------------------------------------
    MIPS	DMTC1	64	iRfR		(Move from GPR to FPR)
        MTC1	32	iRfR
        ??
    ------------------------------------------
    PPC	??

  Convert from Integer to FP

 -------------------------------------------------------------------------------
o	Convert from Integer

    x86	(*) None, see Load Integer
    -----------------------------------------
    Alpha	CVTQS		RR		(QWORD -> S-floating)
        CVTQT		RR		(QWORD -> T-floating)
        CVTQF		RR		(QWORD -> F-floating)
        CVTQG		RR		(QWORD -> G-floating)

        CVTQL		RR		(QWORD -> DWORD) supportion
        CVTLQ		RR		(DWORD -> QWORD) ops.
    ------------------------------------------
    MIPS	CVT.D.W		RR		(DWORD -> D-floating)
        CVT.D.L		RR		(QWORD -> D-floating)
        CVT.S.W		RR		(DWORD -> S-floating)
        CVT.S.L		RR		(QWORD -> S-floating)
    ------------------------------------------
    SPARC	FITOS		RR		(I -> S)
        FITOD		RR		(I -> D)
        FITOQ		RR		(I -> Q)
        FSTOI		RR		(S -> I)
        FDTOI		RR		(D -> I)
        FQTOI		RR		(Q -> I)
        FSTOX		RR		(S -> X)	V9
        FDTOX		RR		(D -> X)	V9
        FQTOX		RR		(Q -> X)	V9
        FXTOS		RR		(X -> S)	V9
        FXTOD		RR		(X -> D)	V9
        FXTOQ		RR		(X -> Q)	V9
    ------------------------------------------
    PPC
    ------------------------------------------
    HPPA	FCNVXFxx	RR		(From Fixed Point -> Float. P)
    ------------------------------------------
    IA-64	FCVT.xf		F1=F2		(from signed)
        FCVT.xuf.pc.sf	F1=F2		(from unsigned)
    ------------------------------------------
    JVM	I2F			(32bit -> F)
        I2D			(32bit -> D)
        L2F			(64bit -> F)
        L2D			(64bit -> D)

  Convert from FP to integer

 -------------------------------------------------------------------------------
o	Round	to Integer

    x86	(*) based on FRNDINT A
    -----------------------------------------
    Alpha	CVTTQ		RR		(T-floating -> QWORD)
        CVTGQ		RR		(G-floating -> QWORD)
    -----------------------------------------
    MIPS	CEIL.L.S   32	RR		(S-floating -> QWORD fixpnt)
        CEIL.L.D   64	RR		(D-flaoting -> QWORD fixpnt)
        CEIL.W.S   32   RR		(S-floating -> DWORD fixpnt)
        CEIL.W.D   64	RR		(D-floating -> DWORD fixpnt)

        FLOOR.L.S  	RR
        FLOOR.L.D  	RR
        FLOOR.W.S	RR
        FLOOR.W.D	RR

        ROUND.L.S	RR
        ROUND.L.D	RR
        ROUND.W.S	RR
        ROUND.W.D	RR

        TRUNC.L.S	RR
        TRUNC.L.D	RR
        TRUNC.W.S	RR
        TRUNC.W.D	RR

        CVT.L.S	        RR		(S -> QWORD) (def. round mode)
        CVT.L.D		RR		(D -> QWORD)
        CVT.W.S		RR		(S -> DWORD)
        CVT.W.D		RR		(D -> DWORD)
    -----------------------------------------
    SPARC	see convert  from integer
    -----------------------------------------
    PPC	FCTIW		RR		(->DWORD) def.round mode
        FCTIWZ		RR		(->DWORD) round toward zero
    -----------------------------------------
    HPPA	FRNDxx		RR		(Round to Integer)
    -----------------------------------------
    IA-64	FCVT.fx.sf	   F1=F2
            .fx.trunc.sf   F1=F2
            .fxu.sf	   F1=F2
            .fxu.trunc.sf  F1=F2
    ------------------------------------------
    68K	FINT.f		[EA],FPn	(Round as FPCR.RND field)
        FINT.X		FPm,FPn
        FINT.X		FPn
        FINTRZ.f	[EA],FPn	(Round to Zero)
        FINTRZ.X	FPm,FPn
        FINTRZ.X	FPn
 -------------------------------------------------------------------------------
o	Store  as Integer (i.e. perform round too)

    x86	FIST	16	AM
            32	AM
            64	AM
    -----------------------------------------
    MIPS	DMFC1	64	iRfR		(Move from  F.P reg to GPR)
        MFC1	32	iRfR
    -----------------------------------------
    SPARC
    -----------------------------------------
    HPPA	FCNVFXxx	RR		(Float.p -> Fixed p.)
        FCNVFXTxx	RR		(--//-- + truncate)
    -----------------------------------------
    JVM	F2I		(F -> DWORD)
        F2L		(F -> QWORD)
        D2I		(D -> DWORD)
        D2L		(D -> QWORD)
 -------------------------------------------------------------------------------

 -------------------------------------------------------------------------------
        TRANCEDENTAL	FUNCTIONS
 -------------------------------------------------------------------------------
o	Cosine

    x86	FCOS		A
        FSINCOS		A
    -----------------------------------------
 -------------------------------------------------------------------------------
o	Sine

    x86	FSINCOS		A
    -----------------------------------------
 -------------------------------------------------------------------------------
o	Tangent

    x86	FPTAN		A		(then some more ops)
    -----------------------------------------
 -------------------------------------------------------------------------------
o	Arctangent

    x86	FPATAN		A		(then some more ops)
    -----------------------------------------
 -------------------------------------------------------------------------------
o	Compute 2^X-1

    x86	F2XM1		A
    -----------------------------------------
 -------------------------------------------------------------------------------
o	Compute y*(log2 x)

    x86	FYL2X		AF
    -----------------------------------------
 -------------------------------------------------------------------------------
o	Compute y*(log2(x+1))

    x86	FYL2XP1		AF
    -----------------------------------------
 -------------------------------------------------------------------------------

 --------------------------------------------------------------------------
    SOME MISC ADDITIONAL FUNCTIONS
 --------------------------------------------------------------------------
o	Absolute Maximum

    IA-64	FAMAX.sf	F1=F2,F3
 --------------------------------------------------------------------------
o	Absolute Minimum

    IA-64	FAMIN.sf	F1=F2,F3
 --------------------------------------------------------------------------
o	F.P. Logical AND

    IA-64	FAND		F1=F2,F3
 --------------------------------------------------------------------------
o	F.P. AND-Complement

    IA-64	FANDCM		F1=F2,F3
 --------------------------------------------------------------------------
o	F.P.  Maximum

    IA-64	FMAX.sf		F1=F2,F3
 --------------------------------------------------------------------------
o	F.P.  Minimum

    IA-64	FMIN.sf		F1=F2,F3
 ------------------------------------------------------------------------
o	F.P.  Logical OR

    IA-64	FOR		F1=F2,F3
 -------------------------------------------------------------------------
o	F.P. Negate Absolute Value

    IA-64	FNEGABS		F1=F3	(Pop: fmerge.ns F1=f0,F3
 --------------------------------------------------------------------------
o	F.P. Reciprocal Approximation

    IA-64	FRCPA		F1,P1=F2,F3
 -------------------------------------------------------------------------
o	F.P. Exclusive OR

    IA-64	FXOR		F1=F2,F3
 --------------------------------------------------------------------------
o	Fixed Point Multiply Add

    IA-64	XMA.l/lu/h/hu	F1=F3,F4,F2
 --------------------------------------------------------------------------
o	Fixed Point Multiply

    IA-64	XMPY.l/lu/h/hu	F1=F3,F4
 --------------------------------------------------------------------------

IA-64 Have many lot operations to mix different fields of F.P. Registers!!!!
Need to look here more carefully

 -------------------------------------------------------------------------

Note:	so, F.P. compares and jumps.
        F.P. round precension control
        F.P. conditional Move
        F.P. unordered comparing

      That also additional CPUs we must to add:
    o      Zilog Z8000
    o      VAX-11.


35.2.3. ЦЕЛОЧИСЛЕННЫЕ ВЕКТОРНЫЕ КОММАНДЫ

  Vector Paralel Addition

Обычный:

    parellel
    {
        destination[i] = source1[i] + source2[i]
    }

Unsigned Saturate:

    parellel
    {
        destination[i] = Unsigned_Saturate(source1[i] + source2[i])
    }

Собственно действия при unsigned saturated add:

Add saturated unsigned:

Signed Saturate:

    parellel
    {
        destination[i] = Signed_Saturate(source1[i] + source2[i])
    }

Собственно действия при signed saturated add:

Add saturated signed:

 ---------------------------------------------------------------------------
VECTOR ADDITION
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PADDB  	PADDW  	PADDD	PADDQ	PADDB  	PADDW  	PADDD	PADDQ
    PADDSB  PADDSW			PADDSB  PADDSW
    PADDUSB PADDUSW			PADDUSB	PADDUSW
    --------------------------------------------------------------------
ia64	PADD1 	PADD2	PADD4
    (.uuu)
    (.uus)
    (.ssi)
    --------------------------------------------------------------------
Alpha
    --------------------------------------------------------------------
MIPS	ADD.OB	ADD.QH
    --------------------------------------------------------------------
PPC					VADDSBS	VADDSHS	VADDSWS
                                    VADDUBM VADDUHM	VADDUWM
                    VADDUBS	VADDUHS	VADDUWS
    --------------------------------------------------------------------
SPARC		FPADD16	FPADD32
 ---------------------------------------------------------------------------

  Vector parallel subtraction

Обчыный:

    parellel
    {
        destination[i] = source1[i] - source2[i]
    }

Unsigned Saturate:

    parellel
    {
        destination[i] = Unsigned_Saturate(source1[i] + source2[i])
    }

Собственно действия при unsigned saturated subtract:

Subtract saturated unsigned:

Signed Saturate:

    parellel
    {
        destination[i] = Signed_Saturate(source1[i] + source2[i])
    }

Собственно действия при signed saturated subtract:

Subtract saturated signed:

 ---------------------------------------------------------------------------
VECTOR SUBTRACTION
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PSUBB	PSUBW	PSUBD	PSUBQ	PSUBB	PSUBW	PSUBD	PSUBQ
    PSUBSB	PSUBSW			PSUBSB	PSUBSW
    PSUBUSB	PSUBUSW			PSUBUSB	PSUBUSW
        --------------------------------------------------------------------
ia64	PSUB1	PSUB2	PSUB4
    (.uuu)
    (.uus)
    (.sss)
        --------------------------------------------------------------------
Alpha
        --------------------------------------------------------------------
MIPS	SUB.OB	SUB.QH
        --------------------------------------------------------------------
PPC					VSUBSBS	VSUBSHS	VSUBSWS
                    VSUBUBM	VSUBUHM	VSUBSWM
                    VSUMUBS	VSUBUHS	VSUMSWS
        --------------------------------------------------------------------
SPARC		FPSUB16	FPSUB32
 ---------------------------------------------------------------------------

  Vector parallel maximum

Операция MAX имеет два различных варианта для Signed и Unsigned чисел.

    parellel
    {                                    U
        destination[i] = (source1[i] >= source2[i])? source1[i] : source2[i]
    }

    parellel
    {                                    S
        destination[i] = (source1[i] >= source2[i])? source1[i] : source2[i]
    }

Собственно действия при maximum:

Unsigned Maximum:

Signed Maximum:

 ---------------------------------------------------------------------------
VECTOR MAXIMUM
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PMAXUB	PMAXSW			PMAXUB	PMAXSW
    --------------------------------------------------------------------
ia64	PMAX1	PMAX2
    --------------------------------------------------------------------
Alpha	MAXUB8	MAXUW4
    MAXSB8	MAXSW4
    --------------------------------------------------------------------
MIPS	MAX.OB	MAX.QH
    --------------------------------------------------------------------
PPC					VMAXSB	VMAXSH	VMAXSW
                    VMAXUB	VMAXUH	VMAXUW
        --------------------------------------------------------------------
SPARC
 ---------------------------------------------------------------------------

  Vector parallel minimum

Операция MIN имеет два различных варианта для Signed и Unsigned чисел.

    parellel
    {                                    U
        destination[i] = (source1[i] < source2[i])? source1[i] : source2[i]
    }

    parellel
    {                                    S
        destination[i] = (source1[i] < source2[i])? source1[i] : source2[i]
    }

Собственно действия при manimum:

Unsigned Manimum:

Signed Manimum:

 ---------------------------------------------------------------------------
VECTOR MINIMUM
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PMINUB	PMINSW			PMINUB	PMINUW
        --------------------------------------------------------------------
ia64	PMIN1	PMIN2
        --------------------------------------------------------------------
Alpha	MINUB8	MINUW4
    MINSB8	MINSW4
        --------------------------------------------------------------------
MIPS	MIN.OB	MIN.QH
        --------------------------------------------------------------------
PPC					VMINSB	VMINSH	VMINSW
                    VMINUB	VMINUH	VMINUW
        --------------------------------------------------------------------
SPARC
 ---------------------------------------------------------------------------

  Vector parallel average sum

Собственно Average - операция одна и таже для знаковых и беззнаковых чисел.

    parellel
    {
        destination[i] = (source1[i] + source2[i] + 1) >> 1
    }

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

Round to odd:

Round away from zero:

 ---------------------------------------------------------------------------
VECTOR AVERAGE SUM
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PAVGB	PAVGW			PAVGB	PAVGW
    --------------------------------------------------------------------
ia64	PAVG1	PAVG2
    --------------------------------------------------------------------
Alpha
    --------------------------------------------------------------------
MIPS
    --------------------------------------------------------------------
PPC					VAVGSB	VAVGSH	VAVGSW
                    VAVGUB	VAVGUH	VAVGUW
    --------------------------------------------------------------------
SPARC
 ---------------------------------------------------------------------------

  Vector Bitwise Logical Operations

    destination = source1 .LOGICAL_OP. source2

 ---------------------------------------------------------------------------
VECTOR BINARY LOGIC OPERATION (ALL)
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
    +----------------------------+ +-----------------------------------+
x86    	PAND				PAND	ANDPS 	ANDPD
    PANDN                           PANDN   ANDNPS  ANDNPD
    POR                             POR     ORPS	ORPD
    PXOR                            PXOR    XORPS	XORPD
    +----------------------------+ +-----------------------------------+
ia64	Standart
    +----------------------------+ +-----------------------------------+
Alpha	Standart
    +----------------------------+ +-----------------------------------+
MIPS	AND.OB	AND.QH
    OR.OB	OR.QH
    NOR.OB	NOR.QH
    XOR.OB	XOR.QH
    +----------------------------+ +-----------------------------------+
PPC					VAND
                    VANDC
                    VNOR
                    VOR
                    VXOR
    +----------------------------+ +-----------------------------------+
SPARC	FOR
    FNOR
    FAND
    FNAND
    FXOR
    FXNOR
    FANDNOT1
    FORNOT1
    FORNOT2
 ---------------------------------------------------------------------------

  Vector parallel shift

    parallel
    {
        destination[i] = source[i] << count
    }

    parallel
    {
        destination[i] = source[i] >> count
    }

    parallel
    {
        destination[i] = source[i] >>> count
    }

 ---------------------------------------------------------------------------
VECTOR SHIFT (ALL)
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86		PSLLW	PSLLD	PSLLQ		PSLLW	PSLLD	PSLLQ	PSLLDQ
        PSRLW	PSRLD	PSRLQ		PSRLW	PSRLD	PSRLQ	PSRLDQ
        PSRAW	PSRAD	?		PSRAW	PSRAD	?	?
        --------------------------------------------------------------------
ia64		PSHL2	PSHL4	(SHL)
        PSHR2	PSHR4	(SHR)
        (.u)	(.u)	(.u)
        --------------------------------------------------------------------
Alpha
        --------------------------------------------------------------------
MIPS	SLL.OB	SLL.QH
    SRL.OB	SRL.QH
    SRA.OB	SRA.QH
        --------------------------------------------------------------------
PPC					VSLB	VSLH	VSLW	VSLO	VSL
                    VSRB	VSRH	VSRW	VSRO	VSR
                    VSRAB	VSRAH	VSRAW	?	?
    --------------------------------------------------------------------
SPARC
 ---------------------------------------------------------------------------

  Vector parallel multiply

Общий вид:

В реальности существуют несколько вариантов умножения:
для обычной арифметики:
    - Multiply Low	(он одинаковый для Signed и Unsigned)
    - Multiply High Signed
    - Multiply High Unsigned
для арифметики с насыщением:
    - Multiply Low Saturated Signed
    - Multiply Low Saturated Unsigned

Multiply Low:

    parallel
    {
        destination[i] = LO(source1[i] * source2[i])
    }

Multiply High (помним что есть два варианта):

    parallel
    {                                       U
        destination[i] = HI(source1[i]  * source2[i])
    }

    parallel
    {                                      S
        destination[i] = HI(source1[i] * source2[i])
    }

Saturated Multiply (есть Signed, есть Unsigned):

    parallel
    {                                                     U
        destination[i] = Unsigned_Saturate(source1[i] * source2[i])
    }

    parallel
    {                                                   S
        destination[i] = Signed_Saturate(source1[i] * source2[i])
    }

Варианты реализации (совсем не оптимизированные):
Saturated Multiply Unsigned:

Saturated Multiply Signed:

Следущий вариант более общий - умножение N*N => 2N, сдвиг на указанное
число битов (и как правило еще и saturation (на рисунке не показано)

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

Vector Multiply Left:

Vector Multiply Right:

Эти формы могут быть как signed, так и unsigned

 ---------------------------------------------------------------------------
VECTOR MULTIPLY (ALL)
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86		PMULHW                          PMULHW
        PMULLW		PMULUDQ		PMULLW		PMULUDQ
        --------------------------------------------------------------------
ia64		PMPY2
        --------------------------------------------------------------------
Alpha
        --------------------------------------------------------------------
MIPS	MUL.OB	MUL.QH
        --------------------------------------------------------------------
PPC					VMULESB	VMULESH
                    VMULOSB	VMULOSH
                    VMULEUB	VMULEUH
                    VMULOUB	VMULOUH
        --------------------------------------------------------------------
SPARC	+------------------------------+
    FMUL8x16
    FMUL8SUx16
    FMULD8SUx16
    FMULD8ULx16
 ---------------------------------------------------------------------------

  Multiply and Add (Accumulate)

THIS SECTION IS UNDER CONSTRUCTION

Multiply and Add:

Multiply and Add Saturated

Обратите внимание, что у этой операции размер элемента target вектора
больше чем у source.

Операция использьзуется для получения dot product.
Соответсвенно востребована в codecs.

 ---------------------------------------------------------------------------
VECTOR MULTIPLY-ADD (ALL)
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86		   PMADDWD			  PMADDWD

        --------------------------------------------------------------------
ia64
        --------------------------------------------------------------------
Alpha
        --------------------------------------------------------------------
MIPS	MULA.OB	MULA.QH
        --------------------------------------------------------------------
PPC				       VMSUMMMM VMSUMSHM
                       VMSUMUBM VMSUMSHS
                                VMSUMUHM
                        VMSUMUHS
        --------------------------------------------------------------------
SPARC
 ---------------------------------------------------------------------------

  Vector sum of absolute difference

THIS SECTION IS UNDER CONSTRUCTION

Обратите внимание, что у этой операции размер элемента target вектора
больше чем у source.

Операция часто используется в codecs.

 ---------------------------------------------------------------------------
VECTOR SUM OF ABSOLUTE DIFFERENCE
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PSADBW				PSADBW
        --------------------------------------------------------------------
ia64	PSAD1
        --------------------------------------------------------------------
Alpha
        --------------------------------------------------------------------
MIPS
        --------------------------------------------------------------------
PPC
        --------------------------------------------------------------------
SPARC
 ---------------------------------------------------------------------------

  Vector Load

Vector load:

Scalar load:

 ---------------------------------------------------------------------------
VECTOR LOAD
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
    +----------------------------+ +-----------------------------------+
x86	MOVD (32)			MOVDQA	MOVDQU
    MOVQ (64)			MOVHPD		(hi part)
                    MOVLPD		(lo part)
    +----------------------------+ +-----------------------------------+
ia64	Standart
    +----------------------------+ +-----------------------------------+
Alpha	Standart
    +----------------------------+ +-----------------------------------+
MIPS	Standart
    (LDC1)
    (LDXC1)
    (LUXC1)
    +----------------------------+ +-----------------------------------+
PPC					LVX
                    LVEBX	(element B)
                    LVEHW	(element W)
                    LVEWX	(element X)
    +----------------------------+ +-----------------------------------+
SPARC	Standart			Standart
    (LDDFA)				(LDDA)	(128-bit 2xFP)
 ---------------------------------------------------------------------------

  Vector store

Vector store

Scalar store

 ---------------------------------------------------------------------------
VECTOR STORE
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
    +----------------------------+ +-----------------------------------+
x86	MOVD (32)			MOVDQA	MOVDQU
    MOVQ (64)			MOVHPD		(hi part)
                    MOVLPD		(lo part)
    +----------------------------+ +-----------------------------------+
ia64	Standart
    +----------------------------+ +-----------------------------------+
Alpha	Standart
    +----------------------------+ +-----------------------------------+
MIPS	Standart
    (SDC1)
    (SDXC1)
    (SUXC1)
    +----------------------------+ +-----------------------------------+
PPC					STVX
                    STVEBX 	(element B)
                    STVEHW	(element H)
                    STVEWX	(element W)
    +----------------------------+ +-----------------------------------+
SPARC	Standart
    (STDFA)
 ---------------------------------------------------------------------------

  Vector parallel compare

 ---------------------------------------------------------------------------
VECTOR PARALLEL COMPARE (ALL)
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PCMPEQB	PCMPEQW	PCMPEQD		PCMPEQB	PCMPEQW	PCMPEQD
    PCMPGTB	PCMPGTW	PCMPGTD		PCMPGTB	PCMPGTW	PCMPGTD
        --------------------------------------------------------------------
ia64	PCMP1	PCMP2	PCMP4
        --------------------------------------------------------------------
Alpha
        --------------------------------------------------------------------
MIPS	C.EQ.OB	C.EQ.QH
    C.LE.OB	C.LE.QH
    C.GT.OB	C.GT.QH
        --------------------------------------------------------------------
PPC				       VCMPEQUB	VCMPEQUH VCMPEQUW
                                       VCMPGTSB VCMPGTSH VCMPGTSW
                       VCMPGTUB VCMPGTUH VCMPGTUW
        --------------------------------------------------------------------
SPARC	       FCMPGT16	FCMPGT32
           FCMPNE16 FCMPNE32
           FCMPLE16 FCMPLE32
           FCMPEQ16 FCMPEQ32
 ---------------------------------------------------------------------------

  Shuffle vector

Наиболее частое использование Vector Shuffle - это распространение скаляра
по векторному регистру (broadcast).

Другой частый пример - это reverse - изменение порядка следования
на обратный:

 ---------------------------------------------------------------------------
VECTOR SHUFFLE
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86		PSHUFW					PSHUFD	SHUFPD
                                                        SHUFPS
        --------------------------------------------------------------------
ia64	MIX1	MIX2	MIX4
    MUX1	MUX2
        --------------------------------------------------------------------
Alpha
        --------------------------------------------------------------------
MIPS	SHFL.PACH.OB
    SHFL.PACK.OB
    SHFL.MIXH.OB
    SHFL.MIXL.OB
        SHFL.PACH.QH
        SHFL.PACK.QH
        SHFL.MIXH.QH
        SHFL.MIXL.QH
        --------------------------------------------------------------------
PPC					VMRGHB	VMRGHH	VMRGHW
        --------------------------------------------------------------------
SPARC	first BMASK
    then  BSHUFFLE
 ---------------------------------------------------------------------------

  Vector pack/unpack

THIS SECTION IS UNDER CONSTRUCTION

Pack:

Unpack High:

Unpack Low:

 ---------------------------------------------------------------------------
VECTOR PACK/UNPACK
        --------------------------------------------------------------------
     64	64	64	64	128	128	128	128	128
    8xB	4xW	2xD	1xQ	16xB	8xW	4xD	2xQ     1xO
        --------------------------------------------------------------------
x86	PACKSSWB			PACKSSWB
    PACKSSDW			PACKSSDW
    PACKUSWD			PACKUSWD
    PUNPCKHBW			PUNPCKHBW
    PUNPCKLBW			PUNPCKLBW
    PUNPCKHWD			PUNPCKHWD
    PUNPCKLWD			PUNPCKLWD
    PUNPCKHDQ			PUNPCKHDQ
    PUNPCKLDQ			PUNPCKLDQ
        --------------------------------------------------------------------
ia64	PACK2
    PACK4
    UNPACK1
    UNPACK2
    UNPACK4
        --------------------------------------------------------------------
Alpha	PKLB
    PKWB
    UNPCKBL
    UNPCKBW
        --------------------------------------------------------------------
MIPS
        --------------------------------------------------------------------
PPC					VPKSHSS
                    VPKSHUS
                    VPKSWSS
                    VPKSWUS
                    VPKUHUM
                    VPKUHUS
                    VPKUWUM
                    VPKUWUS
                    VUPKHPX
                    VUPKHSB
                    VUPKHSH
                    VUPKLPX
                    VUPKLSB
                    VUPKLSH
        --------------------------------------------------------------------
SPARC	FPACK16
    FPACK32
    FEXPAND?
 ---------------------------------------------------------------------------


35.2.3.1. INTEGER VECTOR CODE ISA SUMMARY

+-----------+
|  IA-64    |	PARALLEL INTEGERS
+-----------+

Vector Data Formats:
    [ BYTE x  8  ]	= 64bit
    [ WORD x  4  ]	= 64bit
    [ DWORD x 2  ]	= 64bit

PACK2/PACK4		- Pack
PADD1/PADD2/PADD4	- Parallel Add
PAVG1/PAVG2		- Parallel Average
PAVGSUB1/PAVGSUB2	- Parallel Average Subtract
PCMP1/PCMP2/PCMP4	- Parallel Compare
PMAX1/PMAX2		- Parallel Maximum
PMIN1/PMIN2		- Parallel Minimum
PMPY2			- Parallel Multiply
PMPYSHR2		- Parallel Multiply and Shift Right
POPCNT			- Population Count
PSAD1			- Parallel Sum of Absolute Differences
PSHL2/PSHL4		- Parallel Shift Left
PSHLADD2		- Parallel Shift Left and Add
PSHR2/PSHR4		- Parallel Shift Right
PSHRADD2		- Parallel Shift Right and add
PSUB1/PSUB2/PSUB4	- Parallel Subtract
UNPACK1/UNPACK2/UNPACK4 - Unpack

+-----------+
| Alpha	    |
+-----------+
look like since 21264 only (MVI)

Vector Data Formats:
     [ BYTE x 8 ]	= 64 bit
    [ WORD x 4 ]	= 64 bit

(Not vector, but join with multimedia)				Extension
CTLZ			- Counting Leading Zeroes		CIX
CTPOP			- Count Population			CIX
CTTZ			- Count Trailing Zeroes			CIX
SEXTB			- Sign Extend Byte			BWX
SEXTW			- Sign Extend Word			BWX
            (BWX extension also support unsigned byte load/store)

(Vector)
MINUB8			- Vector Unsigned Byte Minimum		MVI
MINSB8			- Vector Signed Byte Minimum		MVI
MINUW4			- Vector Unsigned Word Minimum		MVI
MINSW4			- Vector Signed Word Minimum		MVI
MAXUB8			- Vector Unsigned Byte Maximum		MVI
MAXSB8			- Vector Signed Byte Maximum		MVI
MAXUW4			- Vector Unsigned Word Maximum		MVI
MAXSW4			- Vector Signed Word Maximum		MVI
PERR			- Pixel Error				MVI
PKLB			- Pack Longwords to Bytes		MVI
PKWB			- Pack Words to Bytes			MVI
UNPKBL			- Unpack bytes to Longwords		MVI
UNPKBW			- Unpack Bytes to Words			MVI

+-------------+
|    x86      |
+-------------+

Main set of Vector Instruction on x86 is MMX (Multimedia Extensions Set).

MMX Instruction Set [Pentium w/MMX, Pentium II]
  -------------------------------------------

    MM Registers (64-bit)

Vector Data Formats:
    [ BYTE  x 8 ]	= 64bit
    [ WORD  x 4 ]	= 64bit
    [ DWORD x 2 ]	= 64bit
    [ QWORD	    ]	= 64bit		(Logic and Shifts only)

MOVQ			- Move 64-bit
PACKSSWB/PACKSSDW	- Pack with Signed Saturation
PACKUSWB		- Pack with Unsigned Saturation
PADDB/PADDW/PADDD	- Packed Add
PADDSB/PADDSW		- Packed Add with Saturation
PADDUSB/PADDUSW		- Packed Add Unsigned with Saturation
PAND			- Bitwise Logical And
PANDN			- Bitwise Logical And-Not
PCMPEQB/PCMPEQW/PCMPEQD - Packed Compare for Equal
PCMPGTB/PCMPGTW/PCMPGTD	- Packed Compare for Greater Than
PMADDWD			- Packed Multiply and Add
PMULHW			- Packed Multiply High
PMULLW			- Packed Multiply Low
POR			- Bitwise Logical Or
PSLLW/PSLLD/PSLLQ	- Packed Shift Left Logical
PSRAW/PSRAD		- Packed Shift Right Arithmetic
PSRLW/PSRLD/PSRLQ	- Packed Shift Right Logical
PSUBB/PSUBW/PSUBD	- Packed Subtract
PSUBSB/PSUBSW		- Packed Subtract with Saturation
PSUBUSB/PSUBUSW		- Packed Subtract Unsigned with Saturation
PUNPCKHBW/PUNPCKHWD/	- Unpack High Packed Data
PUNPCKHDQ
PUNPCKLBW/PUNPCKLWD/	- Unpack Low Packed Data
PUNPCKLDQ
PXOR			- Bitwise Logical Exclusive OR
(below is KNI SIMD instuctions, which is add-on to MMX)
PAVGB/PAVGW		- Packed Average
PEXTRW			- Extract Word
PINSRW			- Insert Word
PMAXSW			- Packed Signed Integer Word Maximum
PMAXUB			- Packed Unsigned Integer Byte Maximum
PMINSW			- Packed Signed Integer Word Minimum
PMINUB			- Packed Unsigned Integer Byte Minimum
PMOVMSKB		- Move Byte Mask To Integer (Mask is sign bits of ops)
PSADBW			- Packed Sum of Absolute Differences
PSHUFW			- Packed Shuffle Word

SIMD2 extensions to MM register operations
PADDQ			- Add
PSUBQ			- Sub

Williamette SIMD2 Extensions [Pentium 4]:
 ------------------------------

    XMM Registers (128-bit)

    [ BYTE  x 16 ]	= 128 bit
    [ WORD  x 8  ]	= 128 bit
    [ DWORD x 4  ]  = 128 bit
    [ QWORD x 2  ]	= 128 bit

PADDB/PADDW/PADDD/PADDQ		- Add
PADDSW/PADDSW			- Add with Saturation
PADDUSB/PADDUSW			- Add with Saturation (Unsigned)
PSUBB/PSUBW/PSUBD/PSUBQ		- Sub
PSUBSB/PSUBSW			- Sub with Saturation
PSUBUSB/PSUBUSW			- Sub with Saturation (Unsigned)

PMULHW/PMULHUW			- Multiply High (W)
PMULLW				- Multiply Low (W)
PMULUDQ				- Multiply Unsigned (DQ)

PSLLW/PSSLD/PSSLQ/PSLLDQ	- Shift Left
PSRLW/PSRLD/PSRLQ/PSRLDQ	- Shift	Right

PANDN				- And Not
PAND				- And
POR				- Or
PXOR				- Xor

PAVGV/PAVGW			- Average
PCMP(EQ/GT)B/W/D		- Compare

PMAXSW/PMAXUB			- Maximum
PMINSW/PMINUB			- Minimum
PSADBW				- Sum of Absolute Differences
PSHUFHW/PSHUFD			- Shuffle
PMADDWD				- Multiply-Add

MOVDQA				- Move aligned
MOVDQU				- Move unalifned
MOVDQ2Q				- XMM => MM
MOVQ2DQ				- MM  => XMM

+---------+
| MIPS    |
+---------+

MDMX - MIPS  Digital Media Extension

    [ 8 x U_BYTE  ]	= 64 bit	OB (Oct Bytes Format)
    [ 4 x U_WORD  ]	= 64 bit	QH (Quad Half Format)

MDMX shared 32 64-bit registers with FPU.

Use existing FPU operations for load vectors and it's parts
    LDC1/LDXC1/LUXC1 - for load
    SDC1/SDXC1/SUXC1 - for store

All instructions have postfixes .OB or .QH:

MSGN				-
C.EQ/C.LT/C.LE			- Compare and Branch?
PICKF/PICKT			-
MIN/MAX				- Minimum/Maximum
ADD/SUB				- Add/Subtract
ADD{A,L}/SUB{A,L}		-
AND/XOR/OR/NOR			- Logical Operations
MUL/MULS{,L}/MUL{A,L}		- Multtiply
SLL/SRL/SRA			- Shifts
ANLI.OB/ANLV.OB			- Align Vector OB format
ANLI.QH/ANLV.QH			- Align Vector QH format
SHFL				- Shuffle
RZU/RNAU/RNEU			-
RZS/RNAS/RNES			-
WAC/RAC				-

Detailed for .OB:
ADD.OB		- Vector Add
ALNI.OB		- Vector Align, Constant ..
AND.OB
C.EQ.OB		- Vector Compare
C.LE.OB
C.GT.OB
MAX.OB		- Vector Maximum
MIN.OB		- Vector Minimum
MUL.OB
MULA.OB		- Vector Multiply Accumulate
MULL.OB		- Vector Multiply and Load accumulator
MULS.OB		- Vector Multiply and Subtract Accumulator
MULSL.OB	- Vector Multiply, Subtract and Load accumulator
NOR.OB
OR.OB
PICKF.OB	- Vector Pick False
PICKT.OB	- Vector Pick True
RACH.OB		- Vector Read Acc High
RACL.OB		- Vector Read Acc Low
RACM.OB		- Vector Read ACC Middle
RZU.OB		- Vector Scale, Round and Clamp Acc
SHFL.PACH.OB	- Shuffle
SHFL.PACL.OB
SHFL.MIXH.OB
SHFL.MIXL.OB
SLL.OB		- Vector Logical Shift Left
SRL.OB
SUB.OB
WACH.OB		- Vector Write Acc High
WACL.OB		- Vector Write Acc Low
XOR.OB

+-----------+
| Power PC  |
+-----------+

PowerPC G4 AntiVect ISA extension:

Vector Data Format:

    V-registers (128 bit)

    [ 16 x SIGNED BYTE	 ] = 128 bit
    [ 16 x UNSIGNED BYTE	 ] = 128 bit
    [ 8  x SIGNED HALFWORD   ] = 128 bit
    [ 8  x UNSIGNED HALFWORD ] = 128 bit
    [ 4  x SIGNED WORD       ] = 128 bit
    [ 4  x UNSIGNED WORD	 ] = 128 bit

LVEBX   - Load Vector Element Byte Indexed
LVEHW	- Load Vector Element Half Word Indexed
LVEWX	- Load Vector Element Word Indexed
LVSL	- Load Vector for shift left
LVSR	- Load Vector for shift rigth
LVX	- Load Vector Indexed
LVXL	- Load Vector Indexed LRU
(MFVSCR) - Move from Vector Status and Control Register
(MTVSCR) - Move to Vector Status and Control Register
STVEBX	 - Store Vector Element Byte Indexed
STVEHX	 - Store Vector Element Half Word Indexed
STVEWX	 - Store Vector Element Word Indexed
STVX	 - Store Vector Indexed
STVXL	 - Store Vector Indexed LRU
VADDCUW	 - Vector Add Carryout Unsigned Word
VADDSBS	 - Vector Add Signed Byte Saturate
VADDSHS	 - Vector Add Signed Half Word Saturate
VADDSWS  - Vector Add Signed Word Saturate
VADDUBM	 - Vector Add Unsigned Byte Modulo
VADDUBS	 - Vector Add Unsigned Byte Saturate
VADDUHM	 - Vector Add Unsigned Half Word Modulo
VADDUHS	 - Vector Add Unsigned Half Word Saturate
VADDUWM	 - Vector Add Unsigned word modulo
VADDUWS	 - Vector Add Unsigned Word Saturate
VAND	 - Vector Logical AND
VANDC	 - Vector Logical AND with Complement
VAVGSB	 - Vector Avarage Signed Byte
VAVGSH	 		  Signed Half Word
VAVGSW			  Signed Word
VAVGUB			  Unsigned Byte
VAVGUH			  Unsigned Half Word
VAVGUW			  Unsigned Word
VCMPEQUB/VCMPEQUB. - Vector Compare Equal-to Unsigned Byte
VCMPEQUH/VCMPEQUH.	                     Unsigned Half Word
VCMPEQUW/VCMPEQUW.			     Unsigned Word
VCMPGTSB/VCMPGTSB. - Vector Compare Greater to Signed Byte
VCMPGTSH/VCMPGTSH.			       Signed Half Word
VCMPGTSW/VCMPGTSW.			       Signed Word
VCMPGTUB/VCMPGTUB.			       Unsigned Byte
VCMPGTUH/VCMPGTUH.			       Unsigned Half Word
VCMPGTUW/VCMPGTUW.			       Unsigned Word
VMAXSB			Vector Maximum	Signed Byte
VMAXSH				Signed Half Word
VMAXSW				Signed Word
VMAXUB				Unsigned Byte
VMAXUH				Unsigned Half Word
VMAXUW				Unsigned Word
VMHADDSHS	Vector Multiply High and Add Signed Half Word Saturate
VMHRADDSHS	Vector Multiply High Round and Add Signed Half Word Saturate
VMINSB		Vector Minimum	Signed Byte
VMINSH				Signed Half Word
VMINSW				Signed Word
VMINUB				Unsigned Byte
VMINUH				Unsigned Half Word
VMINUW				Unsigned Word
VMLADDUHM	Vector Multiply Low and Add Unsigned Half Word Modulo
VMRGHB		Vector Merge High Byte
VMRGHH		Vector Merge High Half Word
VMRGHW		Vector Merge High Word
VMRGLB		Vector Merge Low Byte
VMRGLH		Vector Merge Low Half Word
VMRGLW		Vector Merge Low Word
VMSUMMBM	Vector Multiply Sum Mixed-Sign Byte Modulo
VMSUMSHM	Vector Multiply Sum Signed Half Word Modulo
VMSUMSHS	Vector Multiply Sum Signed Half Word Saturate
VMSUMUBM	Vector Multiply Sum Unsigned Byte Modulo
VMSUMUHM	Vector Multiply Sum Unsigned Half Word Modulo
VMSUMUHS	Vector Multiply Sun Unsigned Half Word Saturate
VMULESB		Vector Multiply Even Signed Byte
VMULESH				     Signed Half Word
VMULEUB				     Unsigned Byte
VMULEUH				     Unsigned Half Word
VMULOSB		Vector Multiply Odd Signed Byte
VMULOSH				    Signed Half Word
VMULOUB				    Unsigned Byte
VMULOUH				    Unsigned Half Word
VNOR		Vector Logical NOR
VOR		Vector Logical OR
VPERM		Vector Permute
VPKPX		Vector Pack Pixel32
VPKSHSS		Vector Pack Signed Half Word Signed Saturate
VPKSHUS		Vector Pack Signed Half Word Unsigned Satuate
VPKSWSS		Vector Pack Signed Word Signed Saturate
VPKSWUS		Vector Pack Signed Word Unsigned Saturate
VPKUHUM		Vector Pack Unsigned Half Word Unsigned Modulo
VPKUHUS		Vector Pack Unsigned Half Word Unsigned Saturate
VPKUWUM		Vector Pack Unsigned Word Unsigned Modulo
VPKUWUS		Vector Pack Unsigned Word Unsigned Saturate
VRLB		Vector Rotate Left Integer Byte
VRLH					   Half Word
VRLW					   Word
VSEL		Vector Conditional Select
VSL		Vector Shift Left
VSLB		Vector Shift Left Integer Byte
VSLDOI		Vector Shift Left Double by Octet Immediate
VSLH		Vector Shift Left Integer Half Word
VSLO		Vector Shift Left by Octet
VSLW		Vector Shift Left Integer Word
VSPLTB		Vector Splat Byte (i.e. write byte to all vector)
VSPLTH			     Half Word
VSPLTW			     Word
VSPLTISB	Vector Splat Immediate Signed Byte
VSPLTISH			       Signed Half Word
VSPLTISW			       Signed Word
VSR		Vector Shift Right
VSRAB		Vector Shift Right Alrebraic Byte
VSRAH					     Half Word
VSRAW					     Word
VSRB		Vector Shift Right Byte
VSRH				   Half Word
VSRW				   Word
VSRO		Vector Shift Right by Octet
VSUBCUW		Vector Subtracted Carryout Unsigned Word
VSUBSBS		Vector Subtract Signed Byte Saturate
VSUBSHS				Signed Half Word Saturate
VSUBSWS				Signed Word Saturate
VSUBUBM		Vector Subtract Unsigned Byte Modulo
VSUBUBS		Vector Subtract Unsigned Byte Saturate
VSUBUHM				Unsigned Half Word Modulo
VSUBUHS				Unsigned Half Word Saturate
VSUBUWM				Unsigned Word Modulo
VSUBUWS				Unsigned Word Saturate
VSUMSWS		Vector Sum Across Signed Word Saturate
VSUM2SWS	Vector Sum Across Partial (1/2) Signed Word Saturate
VSUM4SBS	Vector Sum Across Partial (1/4) Signed Byte Saturate
VSUM4SHS	Vector Sum Across Partial (1/4) Unsigned Half Word Saturate
VSUM4UBS	Vector Sum Across Partial (1/4) Unsigned Byte Saturate
VUPKHPX		Vector Unpack High Pixel16
VUPKHSB		Vector Unpack High Signed Byte
VUPKHSH		Vector Unpack High Signed Half Word
VUPKLPX		Vector Unpack Low Pixel16
VUPKLSB		Vector Unpack Low Signed Byte
VUPKLSH		Vector Unpack Low Signed Half Word
VXOR		Vector Logical XOR

+----------+
| HP-PA 2  |
+----------+

HADD		Halfword parallel add (modular)
HADD,SS		Halfword parallel add (signed saturation)
HADD,US		Halfword parallel add (unsigned saturation)
HAVG		Halfword parallel Average
HSHL		Halfword Parallel shift left
HSHLADD		Halfword Parallel shift left and add
HSHR		Halfword Parallel Shift right (signed)
HSHR,U		Halfword Parallel shift right (unsigned)
HSHRADD		Halfword parallel shift right and add
HSUB		Halfword parallel subtract
HSUB,SS		Halfword parallel subtract (signed saturation)
HSUB,US		Halfword parallel subtract (unsigned saturation)

MIXH,L		Mix Halfwords left
MIXH,R		Mix Halfwords right
MIXW,L		Mix Words Left
MIXW,R		Mix Words right

PERMH		Permute Halfwords


35.2.4.1. FLOATING POINT VECTOR SUMMARY

+-----------+
|  IA-64    |		Floating Point
+-----------+

Vector Data Format:

    [ SINGLE x 2	] = 64 bit

FPABS			- FP Parallel Absolute Value
FPACK			- FP Pack
FPAMAX.sf		- FP Parallel Absolute Maximum
FPAMIN.sf		- FP Parallel Absolute Minimum
FPCMP.frel.sf		- FP Parallel Compare
FPCVT.fx/fxu(.trunc).sf	- Convert Parallel FP to Integer
FPMA.sf			- FP Parallel Multiply Add
FPMAX.sf		- FP Parallel Maximum
FPMERGE.ns/s/se		- FP Parallel Merge
FPMIN.sf		- FP Parallel Minimum
FPMPY.sf		- FP Parallel Multiply
FPMS.sf			- FP Parallel Multiply Subtract
FPNEG			- FP Parallel Negate
FPNEGABS		- FP Parallel Negate Absolute Value
FPNMA.sf		- FP Parallel Negative Multiply Add
FPNMPY.sf		- FP Parallel Negative multiply
FPRCPA.sf		- FPP Reciprocal Apprioximation
FPRSQRTA.sf		- FPP Reciprocal Square Root Approximation

+----------+
| SPARC	   |
+----------+

SPARC V9 Extended Instructions. (UltraSPARC)

    UltraSPACE = V9 + VIS I

Vector Data Format:

    Pixel:		[  BYTE x 4 ] = 32 bit	(8-bit Unsigned Integer)
    Fixed Point:	[  WORD x 4 ] = 64 bit	(16-bit Signed Fixed Point)
    Fixed Point:	[ DWORD x 2 ] = 64 bit	(32-bit Signed Fixed Point)

FPADD16				- Partitioned Add			VIS I
FPADD16S                                                                VIS I
FPADD32                                                                 VIS I
FPADD32S                                                                VIS I
FPSUB16				- Partitioned Subtract                  VIS I
FPSUB16S                                                                VIS I
FPSUB32                                                                 VIS I
FPSUB32S		                                                VIS I
FPACK16				- Pixel formatting                      VIS I
FPACK32									VIS I
FPACKFIX                                                                VIS I
FEXPAND                                                                 VIS I
FPMERGE	                                                                VIS I
FMUL8x16			- Partitioned Multiply             	VIS I
FMUL8x16AU                                                              VIS I
FMUL8x16AL			                                        VIS I
FMUL8SUx16                                                              VIS I
FMUL8ULx16                                                              VIS I
FMULD8SUx16                                                             VIS I
FMULD8ULx16                                                             VIS I
FCMPGT16			- Pixel compare                         VIS I
FCMPGT32                                                                VIS I
FCMPLE16                                                                VIS I
FCMPLE32                                                                VIS I
FCMPNE16                                                                VIS I
FCMPNE32                                                                VIS I
FCMPEQ16                                                                VIS I
FCMPEQ32                                                                VIS I
EDGE8				- Edge handling                         VIS I
EDGE8L                                                                  VIS I
EDGE8N                                                                  VIS II
EDGE8LN                                                                 VIS II
EDGE16                                                                  VIS I
EDGE16L                                                                 VIS I
EDGE16N                                                                 VIS II
EDGE16LN                                                                VIS II
EDGE32                                                                  VIS I
EDGE32L                                                                 VIS I
EDGE32N                                                                 VIS II
EDGE32LN								VIS II
PDIST				- Pixel component Distance		VIS I
LDDFA				- Load Array/etc   			VIS I
LDDA				- Load Quadword atomic			VIS I
STDFA				- Partial store/etc                     VIS I
ARRAY8 				- 3D Array addressing                   VIS I
ARRAY16                                                                 VIS I
ARRAY32                                                                 VIS I
ALIGNADDRESS			- Alignment				VIS I
ALIGNADDRESS_LITTLE                                                     VIS I
FALIGNDATA                                                              VIS I
RDASR				- Read Graphic status reg   		US
WRASR				- Write Graphic status reg  		US
SIAM				- Set Interval Arithmetic mode		VIS II
FZERO		FZEROS		- Logical                               VIS I
FONE		FONES                                                   VIS I
FSRC1		FSRC1S                                                  VIS I
FSRC2		FSRC2S                                                  VIS I
FNOT1		FNOT1S                                                  VIS I
FNOT2		FNOT2S                                                  VIS I
FOR		FORS                                                    VIS I
FNOR		FNORS                                                   VIS I
FAND		FANDS                                                   VIS I
FNAND		FNANDS                                                  VIS I
FXOR		FXORS                                                   VIS I
FXNOR		FXNORS                                                  VIS I
FORNOT1		FORNOT1S                                                VIS I
FORNOT2		FORNOT2S                                                VIS I
FANDNOT1	FANDNOT1S                                               VIS I
FANDNOT2	FANDNOT2S                                               VIS I
BMASK				- Set GSR.MASK for Shuffle instr.	VIS II
BSHUFFLE			- Shuffle 				VIS II

+----------+
| MIPS	   |
+----------+

MIPS V

.PS	[ SINGLE x 2  ] = 64 bit	PS - paired single

LUXC1			- Load PS Unaligned
LDXC1			- Load PS Aligned
LWXC1			- Load PS

SUXC1			- Store PS Unaligned
SDXC1			- Store PS
SWXC1			- Store PS Unaligned

ALNV.PS			- Handled not 8-bit Alignment Vectors

            Example:
                luxc1	f1,bc
                ldxc1	f2,de

                f0	B	C
                f1	D	E

                alnv.ps	f2,f0,f1,T0

                f2	C	D

ADD.PS/	SUB.PS		- Add/Subtract
MUL.PS			- Multiply
ABS.PS			- Absolute Value
MOV.PS			- Move
NEG.PS			- Negate
CVT.S.PU		- Convert from PS Upper to S
CVT.S.PL		- Convert from PS Lower to S
CVT.PS.S		- Convert to PS from 2 S
PLL.PS			- PS from two PS (Low,Low)
PLU.PS			- PS from two PS (Low,Up)
PUL.PS			- PS from two PS (Up,Low)
PUU.PS			- PS from two PS (Up,Up)
C.XX			- FP Vector Compare/Branch

MADD.PS			- Multiply/Add
MSUB.PS			- Multiply/Sub
NMADD.PS		- Negatte Muliply/Add
NMSUB.PS		- Negate Multiply/Sub

MIPS 64 - is superset of MIPS V Instruction Set Architecture.
Contain new data type - paired-single. This datatype prowide 2-way
SIMD capability for two 32-bit single precension floating packed in
one 64-bit register.

Vector Data Format:

.PS	[ SINGLE x 2  ] = 64bit

MIPS-3D ASE (Application Specific Extensions):

ADDR.PS		- F.P. Reduction add
MULR.PS		- F.P. Reduction multiply
RECIP1.S	- Reciprocal with reduced precension result
RECIP1.D
RECIP1.PS
RECIP2.S	- Reciprocal 2nd step
RECIP2.D
RECIP2.PS
RSQRT1.S	- Reciprocal square root with reduced precension result
RSQRT.D
RSQRT.PS
RSQRT2.S	- Reciprocal square root 2nd step
RSQRT2.D
RSQRT2.PS
CVT.PS.PW	- Convert two 32-bit integers to F.P. paired-single
CVT.PW.PS	- Convert F.P paired single to two paired words
CABS.cond.S	- F.P. Absolute Values Compare
CABS.cond.D
CABS.cond.PS
BC1ANY2F cc	- Branch on any of two FP condition code false
BC1ANY2T cc	- Branch on any of two FP condition code true
BC1ANY4F cc	- Branch on any of four FP condition code false
BC1ANY4T cc	- Branch on any of four FP condition code true

+----------+
|  x86	   |
+----------+

KNI (Katmai New Instructions)  SIMD  [Pentium 3]
   ----------------------------------

    XMM Registers (128-bit)

Vector Data Format:

    [ SINGLE x 4 ]	= 128 bit

ADDPS		- Packed Single F.P Add
ANDNPS		- Bit-wide Logical And-Not for Single-FP
ANDPS		- Bit-wide Logical And For Single-FP
CMPPS		- Packed Single-FP Compare
CVTPI2PS	- Packed Signed INT32 to Packed Single-FP Conversion
CVTPS2PI	- Packed Single-FP to Packed INT32 Conversion
CVTTPS2PI	- Packed Single-FP to Packed INT32 Conversion (Truncate)
DIVPS		- Packed Single FP Divide
MAXPS		- Packed Single FP Maximum
MINPS		- Packed Single	FP Minimum
MOVAPS		- Move Aligned Four Packed Single-FP
MOVUPS		- Move Unaligned Four Packed Single-FP
MULPS		- Packed Single-FP Multiply
ORPS		- Bit-wise Logical OR for Single-FP Data
RCPPS		- Packed Single-FP Reciprocal
RSQRTPS		- Packed Single-FP Square Root Reciprocal
SHUFPS		- Shuffle Single-FP
SQRTPS		- Packed Single-FP Square Root
SUBPS		- Packed Single-FP Subtract
XORPS		- Bit-wise Logical XOR for Single-FP Data
(And some other operations)

Williamette SIMD2 Extensions [Pentium 4]:
   -------------------------

    [ DOUBLE x 2 ] = 128 bit

ADDPD		- Add packed Double-FP
ANDNPD		- AND-NOT packed Double-FP
ANDPD		- AND packed Double-FP
CMPxxPD		- Packed Double-FP Compare
DIVPD		- Divide packed Double-FP
MAXPD		- Packed Double-FP Maximum
MINPD		- Packed Double-FP Minimum
MULPD		- Multiply packed Double-FP
ORPD		- OR packed Double-FP
SHUFPD		- Shuffle
SQRTPD		- Packed Double-FP Square Root
SUBPD		- Sub packed Double-FP
XORPD		- XOR packed Double-FP

Also, conversions:
CVTPD2PI	CVTPI2PD
CVTPD2DQ
CVTPD2PS	CVTPS2PD
CVTTPD2PI
CVTTPD2PS

And moving:
MOVAPD		- Aligned
MOVHPD		- High
MOVLPD		- Low
MOVMSKPD	- Byte Mask
MOVUPD		- Unaligned

Packs/Unpacks operations not described here.

Prescott New Instructions (PNI):
  ---------------------------

ADDSUBPD	- Double FP Add/Sub
ADDSUBPS	- Single FP Add/Sub
HADDPD		- Packed double-FP  Horizontal Add
HADDPS		- Packed single-FP  Horizontal Add
HSUBPD		- Packed double-FP  Horizontal Sub
HSUBPS		- Packed single-FP  Horizontal Sub
LDDQU		- Load Unaligned 128-bit integer
MOVDDUP		- Move one double-FP and duplicate
MOVSHDUP	- Move one single-FP high and duplicate
MOVSLDUP	- Move one single-FP low and duplicate

+-----------+
| Power PC  |
+-----------+

PowerPC G4 AntiVect ISA extension:

Vector Data Format:

    V-registers (128 bit)

    [ 4  x SINGLE FP	 ] = 128bit

LVEWX	- Load Vector Element Word Indexed
LVX	- Load Vector Indexed
LVXL	- Load Vector Indexed LRU
STVEWX	 - Store Vector Element Word Indexed
STVX	 - Store Vector Indexed
STVXL	 - Store Vector Indexed LRU
VADDFP	 - Vector Add FP
VCFSX	- Vector Convert from Signed Fixed-point word
VCFUX
VCMPBFP/VCMPBFP.   - Vector Compare Bounds FP
VCMPEQFP/VCMPEQFP. - Vector Compare Equal-to-FP
VCMPGEFP/VCMPEQFP. - Vector compare Greater than or Equal to FP
VCMPGTFP/VCMPGTFP. - Vector compare Greater to FP
VCTSXS		Vector convert to Signed FP Word Saturate
VCTUXS		Vector convert to Unsigned FP Word Saturate
VEXPTEFP	Vector 2 Raised to the Exponent Estimate Floating Point
VLOGEFP		Vector Log2 Estimate Floating Point
VMADDFP		Vector Multiply Add Floating Point
VMAXFP		Vector Maximum Floating Point
VMINFP		Vector Minimum FP
VNMSSUBFP	Vector Negative Multiply-Subtract FP
VREPFP		Vector Reciprocal Estimate FP
VRFIM		Vector Round to FP Integer toward Minus Infinity
VRFIN		Vector Round to FP Integer Nearest
VRFIP		Vector Round to FP Integer toward Plus Infinity
VRFIZ		Vector Round to FP Integer toward Zero
VRSQRTEFP	Vector Reciprocal Square Root Estimate Floating Point
VSUBFP		Vector Subtract FP


35.3. DETAILED INSTRUCTION SET SUMMARY

В этой подглаве описываются кодирование команд из подмножества
Integer Instruction Set для следующих семейств микропроцессоров:

    o  SPARC
    o  Alpha
    o  HP-PA
    o  MIPS
    o  PowerPC
    o  Motorola 68K
    o  Zilog z80
    o  Intel x86
    o  Intel IA-64
    o  JVM (Java Virtual Machine)
    o  Intel MCS51

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

На самом деле для полноты картины не хватает ARM и VAX-11, но просто
не доходят руки :-(


35.3.1 INTEGER ARITHMETICAL INSTRUCTIONS

    Integer Arithmetical Instructions include:

-	Add
-	Subtract
-	Multiply
-	Divide and Remainder

-	Increment
-	Decrement
-	Negate

and also some complex instructions such as
-	Multiply/Add
-	Shift/Add

// ----------------------------------------------------------------------

SPARC

SPARC format 3
+-----------------------+------------------------+
| 31..30	10      | 31..30	10	 |
| 29..25	rd	| 29..25	rd       |
| 24..19	op3	| 24..19	op3      |
| 18..14	rs1	| 18..14	rs1      |
| 13		0	| 13		1        |
| 12..5		---	| 12..0		simm13   |
| 4..0		rs2	|	                 |
+-----------------------+------------------------+

    Opcode		Op3		Operation
    add		00 0000		Add
    addcc		01 0000		Add and modify cc's
    addc		00 1000		Add with carry
    addccc		01 1000		Add with carry and modify cc's

add/addcc/addc/addccc	reg(rs1),reg(rs2),reg(rd)
            reg(rs1),simm13,reg(rd)

r[d] <-  r[rs1] + r[rs2]
r[d] <-  r[rs1] + sign_extend(simm13)

Note: addc/addccc read 32-bit carry flag (CCR.icc.c), not 64-bit
carry flag (CCR.xcc.c)

(On SPARC V8 addc/addccc named ADDX and ADDXcc)

    Opcode		Op 3		Operation
    sub		00 0100		Subtract
    subcc		01 0100		Subtract and modify cc's
    subc		00 1100		Subtract with carry
    subccc		01 1100		Subtract with carry and modify cc's

(On SPARC V8 subc/subccc named SUBX and SUBXcc)

sub/subcc/subc/subccc	reg(rs1),reg(rs2),reg(rd)
            reg(rs1),simm13,reg(rd)

r[d] <-  r[rs1] - r[rs2]
r[d] <-  r[rs1] - sign_extend(simm13)

    Opcode		Op3		Operation
    umul		00 1010		Unsigned Integer Multiply (32bit)
    smul		00 1011		Signed Integer Multiply (32-bit)
    umulcc		01 1010		Unsigned Integer Multiply and
                    modify cc's (32-bit)
    smulcc		01 1011		Signed Integer Multiply and
                    modify cc's (32-bit)
    mulx		00 1001		Multiply (Signed or Unsigned) (64-bit)

r[d] <-  r[rs1] * r[rs2]
r[d] <-  r[rs1] * sign_extend(simm13)

    Opcode		Op 3		Operation
    udiv		00 1110		Unsigned Integer Divide
    sdiv		00 1111		Signed Integer Divide
    udivcc		01 1110		Unsigned Integer Divide and modify cc's
    sdivcc		01 1111		Signed Integer Divide and modify cc's
    sdivx		10 1101		Signed Divide (64-bit)
    udivx		00 1101		Unsigned Divide(64-bit)

r[d] <-  r[rs1] / r[rs2]
r[d] <-  r[rs1] / sign_extend(simm13)

OTHER OPERATION IMPLEMENTATION

- Increment by 1
    add	rx,1,rx

- Decrement by 1
    sub	rx,1,rx

- Negate
    sub	r0,rx,rx

ALPHA

Alpha Operate Format
+-------------------------+------------------------+
| 31..26	Opcode	  | 31..26	Opcode	   |
| 25..21	Ra	  | 25..21	Ra	   |
| 20..16	Rb	  | 20..13	LIT        |
| 15..13	SBZ	  | 12		1          |
| 12		0	  | 11..5	Function   |
| 11..5		Function  | 4..0	Rc         |
| 4..0		Rc        |                        |
+-------------------------+------------------------+

Longword Add
    ADDL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    ADDL	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- SEXT( (Rav + Rbv)<31:0>)

    /V	Integer Overflow Enable

Quadword Add
    ADDQ	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    ADDQ	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav + Rbv

    /V	Integer Overflow Enable

    ADDL	10.00
    ADDL/V	10.40
    ADDQ	10.20
    ADDQ/V	10.60

    // -----------------------------------------------------------------

Longword Subtract
    SUBL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    SUBL	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- SEXT((Rav - Rbv)<31:0>)

    /V	Integer Overflow Enable

Quadword Subtract
    SUBQ	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    SUBQ	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav - Rbv

    /V	Integer Overflow Enable

    SUBL	10.09
    SUBL/V	10.49
    SUBQ	10.29
    SUBQ/V	10.69

    // -----------------------------------------------------------------

Scaled Longword Add
    S4ADDL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S4ADDL	Ra.rq,#b.ib,Rc.wq	!Operate Format
    S8ADDL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S8ADDL	Ra.rq,#b.ib,Rc.wq	!Operate Format

    S4ADDL:
    Rc  <- SEXT (Rav * 4 + Rbv)<31:0>)

    S8ADDL:
    Rc  <- SEXT( (Rav * 8 + Rbv)<31:0>)

Scaled Longword Subtract
    S4SUBL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S4SUBL	Ra.rq,#b.ib,Rc.wq	!Operate Format
    S8SUBL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S8SUBL	Ra.rq,#b.ib,Rc.wq	!Operate Format

    S4SUBL:
    Rc  <- SEXT (Rav * 4 - Rbv)<31:0>)

    S8SUBL:
    Rc  <- SEXT( (Rav * 8 - Rbv)<31:0>)

Scaled Quadword Add
    S4ADDQ	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S4ADDQ	Ra.rq,#b.ib,Rc.wq	!Operate Format
    S8ADDQ	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S8ADDQ	Ra.rq,#b.ib,Rc.wq	!Operate Format

    S4ADDQ:
    Rc  <- Rav * 4 + Rbv

    S8ADDQ:
    Rc  <- Rav * 8 + Rbv

Scaled Quadword Subtract
    S4SUBQ	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S4SUBQ	Ra.rq,#b.ib,Rc.wq	!Operate Format
    S8SUBQ	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    S8SUBQ	Ra.rq,#b.ib,Rc.wq	!Operate Format

    S4ADDQ:
    Rc  <- Rav * 4 - Rbv

    S8ADDQ:
    Rc  <- Rav * 8 - Rbv

    S4ADDL	10.02
    S4SUBL	10.0B
    S4ADDQ	10.22
    S4SUBQ	10.2B

    S8ADDL	10.12
    S8SUBL	10.1B
    S8ADDQ	10.32
    S8SUBQ	10.3B

    // -----------------------------------------------------------------

Longword Multiply
    MULL	Ra.rq,Rb.rq,Rc.rq	!Operate Format
    MULL	Ra.Rq,#b.ib,Rc.wq	!Operate Format

    Rc <- SEXT((Rav*Rbv)<31:0>)

Quadword Multiply
    MULQ	Ra.rq,Rb.rq,Rc.rq	!Operate Format
    MULQ	Ra.Rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav * Rbv (Signed)

Unsigned Quadword Multiply High
    UMULH	Ra.rq,Rb.rq,Rc.rq	!Operate Format
    UMULH	Ra.Rq,#b.ib,Rc.wq	!Operate Format

    Rc <- {Rav *U Rbv} <127:64>

    MULL	13.00
    MULL/V	13.40
    MULQ	12.20
    MULQ/V	13.60
    UMULH	13.30

OTHER OPERATION IMPLEMENTATION

    DIV not exits on Alpha and Realized as Library Functions.
It's because of High-Speed RISC Architecture..

HP-PA

ADD,cond	r1,r2,t			ADDL,cond	r1,r2,t
+---------------------------+
|	Len	Value       |
|	6	02          |		02
|	5	r2          |		r2
|	5	r1          |		r1
|	3	c	    |		c
|	1	f           |		f
|	6	xx          |		28
|	1	0	    |		0
|	5	t	    |		t
+---------------------------+

Command				xx
ADD,cond	r1,r2,t		18	Add, set C/B flag
ADDL,cond	r1,r2,t		28	Add, not set C/B flag
ADDO,cond	r1,r2,t		38	Add, set C/B flag, trap on overflow
ADDC,cond	r1,r2,t		1C	Add with carry, set C/B
ADDCO,cond	r1,r2,t		3C	Add w/carry, set C/B, trap on overflow

    GR[t] <- GR[r1] + GR[r2];
    PSW[C/B] <- carry_borrow;		(set C/B flag only)
    if (cond_satisfied) PSW[N] <- 1

Command				xx
SH1ADD,cond	r1,r2,t		19	Shift one and Add, set C/B
SH1ADDL,cond	r1,r2,t		29	Shift one and Add, not set C/B
SH1ADDO,cond	r1,r2,t		39	Shift one and Add, set C/B, trap on OVF
SH2ADD,cond	r1,r2,t		1A	Shift two and Add, set C/B
SH2ADDL,cond	r1,r2,t		2A	Shift two and Add, not set C/B
SH2ADDO,cond	r1,r2,t		3A	Shift two and Add, set C/B, trap on OVF
SH3ADD,cond	r1,r2,t		1B	Shift 3 and Add, set C/B
SH3ADDL,cond	r1,r2,t		2B	Shift 3 and Add, not set C/B
SH3ADDO,cond	r1,r2,t		3B	Shift 3 and Add, set C/B, trap on OVF

    GR[t] <- lshift(GR[r1],shift_val) + GR[r2]
    if (Overflow)
    {
        Overflow flag)
    } else {
        PSW[C/B] <- carry_borrow;		(set C/B flag only)
        if (cond_satisfied) PSW[N] <- 1
    }

Command				xx
SUB,cond	r1,r2,t		10	Subtract, set C/B
SUBO,cond	r1,r2,t		30	Subtract, set C/B, trap on OVF
SUBB,cond	r1,r2,t		14	Subtract with borrow, set C/B
SUBBO,cond	r1,r2,t		34	Subtract with borrow, set C/B,
                    trap on Overflow
SUBT,cond	r1,r2,t		13	Subtract and trap on condition
SUBTO,cond	r1,r2,t		33	Subtract and trap on condition or
                    overflow

    GR[t] <- GR[r1] + ~GR[r2] + 1;
    PSW[C/B] <- carry_borrow;		(set C/B flag only)
    if (cond_satisfied) PSW[N] <- 1

DS,cond		r1,r2,t		11	Divide Step
                    (Primitive Operation for Integer
                    Diision)

    if (PSW[V])
    {
        GR[t] <- cat(GR[r1]<<1, PSW[C/B]{0}) + ~GR[r2] + 1;
    } else
        GR[t] <- cat(GR[r1]<<1, PSW[C/B]{0}) + GR[r2];
    }
    PSW[C/B] <- carry_borrow
    PSW[V]   <- xor(carry_borrows{0},GR[r2]{0});
    if (cond_satisfied) PSW[N] <- 1;

+---------------------------+
|	Len	Value       |
|	6	zz          |
|	5	r           |
|	5	t           |
|	3	c	    |
|	1	f           |
|	1	z	    |
|	11	im11	    |
+---------------------------+

                zz.z
ADDI,cond	i,r,t		2D.0	Add Immediate
ADDIO,cond	i,r,t		2D.1	Add Immediate and Trap on Overflow
ADDIT,cond	i,r,t		2C.0	Add Immediate and Trap on Condition
ADDITO,cond	i,r,t		2C.1	Add Immediate and Trap on Condition
                    or overflow
SUBI,cond	i,r,t		25.0	Sub Immediate
SUBIO,cond	i,r,t		25.1

OTHER INSTRUCTION IMPLEMENTATION

Multiply is Superpositions of Add and shifts
Division is used special instruction DS (Divide Step)

MIPS

+------------------------------+
|	Len	Value
|	6	0
|	5	rs
|	5	rt
|	5	rd
|	5	0
|	5	xx
+------------------------------+

Command				xx
ADD	rd,rs,rt		10 0000		Add
ADDU	rd,rs,rt		10 0001		Add Unsigned
DADD	rd,rs,rt		10 1100		Doubleword Add
DADDU	rd,rs,rt		10 1101		Doubleword Add Unsigned

    rd <- rs + rt

DDIV	rs,rt			01 1110		Doubleword Divide Signed
DDIVU	rs,rt			01 1111		Doubleword Divide Unsigned
DIV	rs,rt			01 1010		Divide Signed Word
DIVU	rs,rt			01 1011		Divide Unsigned Word
    {in opcode rd = 0}

    (LO,HI) <- rs / rt		(LO - div, HI - mod)

DMULT	rs,rt			01 1100		Doubleword Signed Multiply
DMULTU	rs,rt			01 1101		Doubleword Unsigned Multiply
MULT	rs,rt			01 1000		Multiply Word Signed
MULTU	rs,rt			01 1001		Multiply Word Unsigned
    {in opcode rd = 0}

    (LO,HI) <- rs * rt

SUB	rd,rs,rt		10 0010		Subtract word
SUBU	rd,rs,rt		10 0011		Subtract unsigned word
DSUB	rd,rs,rt		10 1110		Doubleword subtract
DSUBU	rd,rs,rt		10 1111		Doubleword subtract unsigned

    rd <- rs - rt

+------------------------+
|	Len	Value    |
|	6	00 1000  |
| 	5	rs       |
|	5	rt       |
|	16	immm     |
+------------------------+

ADDI	rt,rs,imm	00 1000		Add Immediate Signed
ADDIU	rt,rs,imm	00 1001		Add Immediate Unsigned
DADDI	rt,rs,imm	01 1000		Add Doubleword immediate signed
DADDIU	rt,rs,imm	01 1001		Addd Doubleword immediate unsigned

    rt <- rs + imm

NOTE

    Use MFHI and MFLO operations for Load Data from LO,HI registers

PowerPC

0..5	opcode1
6..10	D
11..15	A
16..20	B
21	OE
22.30	opcode2
31	Rc

                    (DEC).(DEC)
            OE  	Rc	opcode1.opcode2
add	rD,rA,rB	0	0	31.266		Add
add.	rD,rA,rB	0	1
addo	rD,rA,rB	1	0
addo.	rD,rA,rB	1	1

addc	rD,rA,rB	0	0	31.10		Add Carrying
addc.	rD,rA,rB	0	1
addco	rD,rA,rB	1	0
addco.	rD,rA,rB	1	1

    rD <- rA + rB

adde	rD,rA,rB	0	0	31.138		Add Extended
adde.	rD,rA,rB	0	1
addeo	rD,rA,rB	1	0
addeo.	rD,rA,rB	1	1

    rD <- rA + rB + XER[CA]

divw	rD,rA,rB	0	0	31.491		Divide word
divw.	rD,rA,rB	0	1
divwo	rD,rA,rB	1	0
divwo.	rD,rA,rB	1	1

    rD <- rA / rB		(signed)

divwu	rD,rA,rB	0	0	31.459		Divide word unsigned
divwu.	rD,rA,rB	0	1
divwuo	rD,rA,rB	1	0
divwuo.	rD,rA,rB	1	1

    rD <- rA / rB		(unsigned)

mulhw	rD,rA,rB	0	0	31.75		Multiply High word
mulhw.	rD,rA,rB	0	1

    tmp[0-63] <- rA[32-63] * rB[32-63]	(Signed)
    rD[32-63] <- tmp[0-31]
    rD[0-31]  <- UNDEFINED

mulhwu	rD,rA,rB	0	0	31.11		Multiply High word
mulhwu.	rD,rA,rB	0	1			Unsigned

    tmp[0-63] <- rA[32-63] * rB[32-63]	(Unsigned)
    rD[32-63] <- tmp[0-31]
    rD[0-31]  <- UNDEFINED

mullw	rD,rA,rB	0	0	31.235		Multiply Low
mullw.	rD,rA,rB	0	1
mullwo	rD,rA,rB	1	0
mullwo.	rD,rA,rB	1	1

    rD <- rA[32-63] * rB[32-63]

subf	rD,rA,rB	0	0	31.40		Subtract from
subf.	rD,rA,rB	0	1
subfo	rD,rA,rB	1	0
subfo.	rD,rA,rB	1	1
subfc	rD,rA,rB	0	0	31.8		Subtract from
subfc.	rD,rA,rB	0	1			Carrying
subfco	rD,rA,rB	1	0
subfco.	rD,rA,rB	1	1

    rD <- ~rA + rB + 1

subfe	rD,rA,rB	0	0	31.136		Subtract from
subfe.	rD,rA,rB	0	1			Extended
subfeo	rD,rA,rB	1	0
subfeo.	rD,rA,rB	1	1

    rD <- ~rA + rB + XER[CA]

        // ----------------------------------------------------------

0..5	opcode1
6..10	D
11..15	A
16..20	0s
21	OE
22.30	opcode2
31	Rc

addme	rD,rA		0	0	31.234		Add to Minus one
addme.	rD,rA		0	1			Extended
addmeo	rD,rA		1	0
addmeo.	rD,rA		1	1

    rD <- rA + XER[CA] - 1

addze	rD,rA		0	0	31.202		Add to zero
addze.	rD,rA		0	1			extended
addzeo	rD,rA		1	0
addzeo.	rD,rA		1	1

    rD <- rA + XER[CA]

neg	rD,rA		0	0	31.104		Negate
neg.	rD,rA		0	1
nego	rD,rA		1	0
nego.	rD,rA		1	1

    rD <- ~ rA + 1

subfme	rD,rA		0	0	31.232		Subtract from Minus
subfme.	rD,rA		0	1			One Extended
subfmeo	rD,rA		1	0
subfmeo. rD,rA		1	1

    rD <- ~rA + XER[CA] - 1

subfze	rD,rA		0	0	31.200		Subtract from Zero
subfze.	rD,rA		0	1			One Extended
subfzeo	rD,rA		1	0
subfzeo. rD,rA		1	1

    rD <- ~rA + XER[CA]

        // ----------------------------------------------------------

0..5	opcode1
6..10	D
11..15	A
16..31	SIMM

            (DEC)
            opcode1
addi	rD,rA,SIMM	14		Add Immediate

    if rA = 0 then rD <- EXTS(SIMM)
    else	       rD <- rA + EXTS(SIMM)

addic	rD,rA,SIMM	12		Add Immediate Carrying
addic.	rD,rA,SIMM	13		Add Immediate Carrying and Record

    rD <- rA + EXTS(SIMM)

addis	rD,rA,SIMM	15		Add Immediate Shifted

    if rA = 0 then rD <- (SIMM << 16)
    else	       rD <- rA + (SIMM << 16)
                    (Used for load value in high word)

mulli	rD,rA,SIMM	07		Multiply Low Immediate

    tmp[0-48] <- rA * SIMM
    rD <- tmp[16-48]

subfic	rD,rA,SIMM	08		Subtract from Immediate Carrying

    rD <- ~rA + EXTS(SIMM) + 1

68K

Code			Size	Mnemonic		Description
1101nnn0ss<-EA->	B,W,L	ADD	Dn,		Dn +  ->
1101nnn1ss<-EA->	B,W,L	ADD	,Dn		 + Dn -> Dn

1101nnns11<-EA->	W,L	ADDA	,An		 + An  -> An
00000110ss<-EA->	B,W,L	ADDI	#Im,	 + #Im ->
0101xxx0xx<-EA->	B,W,L	ADDQ	#x,		 + #x  ->
                             #x=1..8
1101yyy1ss000xxx	B,W,L	ADDX	Dy,Dx		Dx + Dy + X -> Dx
1101yyy1ss001xxx	B,W,L	ADDX	-(Ay),-(Ax)	 +  + X
                            ->
    - - - - - - - - -
1000nnn111<-EA->	32->16	DIVS	,Dn		Dn/ -> Dn
                            [signed]
1000nnn011<-EA->	32->16 	DIVU	,Dn		Dn/ -> Dn
                            [unsigned]

1100nnn111<-EA->	16->32	MULS	,Dn		Dn *  -> Dn
                            [signed]
1100nnn011<-EA->	16->32	MULU	,Dn		Dn *  -> Dn
                            [unsigned]
        - - - - - - - - -
01000100ss<-EA->	B,W,L	NEG			0 -  ->
01000000ss<-EA->	B,W,L	NEGX			0 -  - X ->

1001nnn0ss<-EA->	B,W,L	SUB	,Dn		Dn -  -> Dn
1001nnn1ss<-EA->	B,W,L	SUB	Dn,		 - Dn ->
1001nnns11<-EA->	W,L	SUBA	,An		An -  -> An
00000100ss<-EA->	B,W,L	SUBI	#Im,	 - #Im ->
0101xxx1ss<-EA->	B,W,L	SUBQ	#x,		 - #x  ->
                            #x = 1..8
1001yyy1ss000xxx	B,W,L	SUBX	Dy,Dx		Dx - Dy - X -> Dy
1001yyy1ss001xxx	B,W,L	SUBX	-(Ay), -(Ax)	-(Ax) - -(Ay) -X -> (Ay)

 =============== Since MC68020: ======================
0100110000<-EA->	L	MULS.L	,Dn		Dn *  -> Dn
0lll10000000hhhh					(32x32->32) Signed

0100110000<-EA->	L	MULS.L	,Dn:Dh	Dn *  -> Dn:Dh
0lll11000000hhhh					(32x32->64) Signed

0100110000<-EA->	L	MULU.L	,Dn		Dn *  -> Dn
0lll00000000hhhh					(32x32->32) Unsigned

0100110000<-EA->	L	MULU.L	,Dn:Dh	Dn *  -> Dn:Dh
0lll01000000hhhh					(32x32->64) Unsigned

0100110001<-EA->	L	DIVS.L	,Dq		Dq /  -> Dq
0qqq100000000rrr

0100110001<-EA->	L	DIVS.L	,Dr:Dq	Dr:Dq /  -> Dr:Dq
0qqq110000000rrr

0100110001<-EA->	L	DIVU.L	,Dq		Dq /  -> Dq
0qqq000000000rrr

0100110001<-EA->	L	DIVU.L	,Dr:Dq	Dr:Dq /  -> Dr:Dq
0qqq010000000rrr

Z80

Operation		Description			Code
ADC	A,r		A <- A + r + Cy			88+r
ADC	A,n		A <- A + n + Cy			CE n
ADD	A,(ii+n)	A <- A + (ii+n) + Cy		ii 8E
ADC	HL,rr		HL <- HL + rr + Cy		ED 01xx1010

ADD	A,r		A <- A + r			80+r
ADD	A,n		A <- A + n			C6 n
ADD	A,(ii+n)	A <- A + (ii+n)			ii 86 n
ADD	HL,rr		HL <- HL + rr			00xx1001
ADD	IX,ry		IX <- IX + ry			ii 00xx1001
ADD	IY,rx		IY <- IY + ry			ii 00xx1001

DEC	r		r --				00xxx101
DEC	(ii+n)		(ii+n) --			ii 35 n
DEC	rr		rr --				00xx1011
DEC	ii		ii --				ii 2B

INC	r		r ++				00xxx100
INC	(ii+n)		(ii+n) ++			ii 34 n
INC	rr		rr ++				00xx0011
INC	ii		ii ++				ii 23

NEG			A <- 0 - A			ED 44

SBC	A,r		A <- A - r - Cy			98+r
SBC	A,n		A <- A - n - Cy			DE n
SBC	A,(ii+n)	A <- A - (ii+n) - Cy		ii 9E n
SBC	HL,rr		HL <- HL - rr - Cy		ED 01xx0010

SUB	r		A <- A - r			90+r
SUB	n		A <- A - n			D6 n
SUB	(ii+n)		A <- A - (ii+n)			ii 96 n

X86

    (Add with Carry) =================
ADC	AL,imm8			14 	ib
ADC	AX,imm16		15 	iw
ADC	EAX,imm32		15	id
ADC	r/m8,imm8		80/2	ib
ADC	r/m16,imm16		81/2	iw
ADC	r/m32,imm32		81/2	id
ADC	r/m16,imm8		83/2	iw
ADC	r/m32,imm8		83/2	iw
ADC	r/m8,r8			10/r
ADC	r/m16,r16		11/r
ADC	r/m32,r32		11/r
ADC	r8,r/m8			12/r
ADC	r16,r/m16		13/r
ADC	r32,r/m32		13/r

    DEST <- DEST + SRC + CF

    (Add) ===========================
ADD	AL,imm8			04 	ib
ADD	AX,imm16		05 	iw
ADD	EAX,imm32		05	id
ADD	r/m8,imm8		80/0	ib
ADD	r/m16,imm16		81/0	iw
ADD	r/m32,imm32		81/0	id
ADD	r/m16,imm8		83/0	iw
ADD	r/m32,imm8		83/0	iw
ADD	r/m8,r8			00/r
ADD	r/m16,r16		01/r
ADD	r/m32,r32		01/r
ADD	r8,r/m8			02/r
ADD	r16,r/m16		03/r
ADD	r32,r/m32		03/r

    DEST <- DEST + SRC

    (Subtract) ========================
SUB	AL,imm8			2C 	ib
SUB	AX,imm16		2D 	iw
SUB	EAX,imm32		2D	id
SUB	r/m8,imm8		80/5	ib
SUB	r/m16,imm16		81/5	iw
SUB	r/m32,imm32		81/0	id
SUB	r/m16,imm8		83/5	iw
SUB	r/m32,imm8		83/5	iw
SUB	r/m8,r8			28/r
SUB	r/m16,r16		29/r
SUB	r/m32,r32		29/r
SUB	r8,r/m8			2A/r
SUB	r16,r/m16		2B/r
SUB	r32,r/m32		2B/r

    DEST <- DEST - SRC

    (Subtract wih borrow) ============
SBB	AL,imm8			2C 	ib
SBB	AX,imm16		2D 	iw
SBB	EAX,imm32		2D	id
SBB	r/m8,imm8		80/5	ib
SBB	r/m16,imm16		81/5	iw
SBB	r/m32,imm32		81/0	id
SBB	r/m16,imm8		83/5	iw
SBB	r/m32,imm8		83/5	iw
SBB	r/m8,r8			28/r
SBB	r/m16,r16		29/r
SBB	r/m32,r32		29/r
SBB	r8,r/m8			2A/r
SBB	r16,r/m16		2B/r
SBB	r32,r/m32		2B/r

    DEST <- DEST - (SRC + CF)

    (Decrement by 1) ===============
DEC	r/m8			FE/1
DEC	r/m16			FF/1
DEC	r/m32			FF/1
DEC	r16			48+rw
DEC	r32			48+rd

    DEST <- DEST - 1

    (Increment by 1) ==============
INC	r/m8			FE/0
INC	r/m16			FF/0
INC	r/m32			FF/0
INC	r16			40+rw
INC	r32			40+rd

    DEST <- DEST + 1

    (Unsigned Divide) ==================
DIV	r/m8			F6/6
DIV	r/m16			F7/6
DIV	r/m32			F7/6

    Quotient  <- Divident / Divisor			(UnSigned)
    Remainder <- Divident MOD Divisor		(UnSigned)

    Divident Divisor  Quotient  Remainder
    AX	  r/m8	    AL	      AH
    DX:AX	  r/m16	    AX        DX
    EDX:EAX	  r/m32	    EAX       EDX

    (Signed Divide) ====================
IDIV	r/m8			F6/7
IDIV	r/m16			F7/7
IDIV	r/m32			F7/7

    Quotient  <- Divident / Divisor			(Signed)
    Remainder <- Divident MOD Divisor		(Signed)

    Divident Divisor  Quotient  Remainder
    AX	  r/m8	    AL	      AH
    DX:AX	  r/m16	    AX        DX
    EDX:EAX	  r/m32	    EAX       EDX

    (Signed Multiply) ===================
IMUL	r/m8			F6/5
IMUL	r/m16			F7/5
IMUL	r/m32			F7/5
IMUL	r16,r/m16		0F AF /r
IMUL	r32,r/m32		0F AF /r
IMUL	r16,r/m16,imm8		6B /r ib
IMUL	r32,r/m32,imm8		6B /r ib
IMUL	r16,imm8		6B /r ib
IMUL	r32,imm8		6B /r ib
IMUL	r16,r/m16,imm16		69 /r iw
IMUL	r32,r/m32,imm32		69 /r id
IMUL	r16,imm16		69 /r iw
IMUL	r32,imm32		69 /r id

    result <- multiplicand * multiplier

    (Unsigned Multiply) =================
MUL	r/m8			F6/4
MUL	r/m16			F7/4
MUL	r/m32			F7/4

    AX <-  AL * r/m8
    or
    DX:AX <- AX * r/m16
    or
    EDX:EAX <- EAX * r/m32

    (Negate) ============================
NEG	r/m8			F6/3
NEG	r/m16			F7/3
NEG	r/m32			F7/3

    if r/m = 0 then CF <- 0 else CF <- 1
    r/m <- 0 - r/m

Note:	FPU Enable to Load 64bit Integers as FP and Provide operations
on it. Because on Extended precension significand is 64bit too, this
scheme will be work.

IA64

Format  A1		Format  A2	       Format A3
------------	+     -------------	+     ------------
40..37	8		40..37	8	       	40..37	8
36	--		36	--		36	S
35..34	X2a		35..34	X2a		35..34	X2a
33	Ve		33	Ve		33	Ve
32..29	X4		32..29	X4		32..29	X4
28..27	X2b		28..27	CT2d		28..27	X2b
26..20	R3		26..20	R3		26..20	R3
19..13	R2		19..13	R2		19..13	Imm7b
12..6	R1		12..6	R1		12..6	R1
5..0	QP		5..0	QP		5..0	QP
------------	+     --------------	+     -------------

Format  A4	         Format A5
------------	+      ------------
40..37	8		40..37	9
36	S		36	S
35..34	X2a		35..27	Imm9d
33	Ve		26..22	Imm5c
32..27	Imm6d		21..20	r3
26..20	R3		19..13	Imm7b
19..13	Imm7b		12..6	R1
12..6	R1		5..0	QP
5..0	QP1
------------	+     -------------

add		r1=r2,r3	A1	8.0.0.0.0
                        r1 <- r2 + r3
add		r1=r2,r3,1	A1	8.0.0.0.1
                        r1 <- r2 + r3 + 1

adds		r1=imm14,r3	A4	8.2.0	r1 <- sext(imm14) + r3
addl		r1=imm22,r3	A5	9	r1 <- sext(imm22) + r3

addp4		r1=r2,r3	A1	8.0.0.2.0  Add Pointer
addp4		r1=imm14,r3	A4	8.3.0	   Add Pointer

shladd		r1=r2,cnt2,r3	A2	8.0.0.4	r1 <- (r2 << cnt2) + r3
shladdp4	r1=r2,cnt2,r3	A2	8.0.0.6 Shift Left and Add Pointer

sub		r1=r2,r3	A1	8.0.0.1.1
                        r1 <- r2 - r3
sub		r1=r2,r3,1	A1	8.0.0.1.0
                        r1 <- r2 - r3 - 1
sub		r1=imm8,r3	A3	8.0.0.9.1
                        r1 <- sext(imm8) - r3

Note:
xma.l/xma.lu/xma.h/xma.hu  	- Fixed Point Multiply Add
xmpy.l/xmpy.lu/xmpy.h/xmpy.hu	- Fixed Point Multiply
    (both are on float registers)

Note:	All other Integer operations such as Multiply, Divide, Negate
are complex operations.

    Add with carry look like

        (predicate)	add	r1=r2,r3
        (predicate)	add	r1=r2,r3,1
So, execution use predicates for select way, on which this instruction
will be executed.

JVM

IADD		60h			(a + b)		32
        {
        POP.I		I1
        POP.I		I2
        PUSH.I		I1+I2
        }

LADD		61h                     (a + b)		64
        {
        POP.L		L1
        POP.L		L2
        PUSH.L		I1+I2
        }

ISUB		64h		       (a - b)		32
LSUB		65h                    (a - b)		64
IMUL		68h                    (a * b)		32
LMUL		69h                    (a * b)		64
IDIV		6ch                    (a / b)		32
LDIV		6dh                    (a / b)		64
IREM		70h                    (a % b)		32
LREM		71h                    (a % b)		64
INEG		74h                    (-a)		32
LNEG		75h                    (-a)             64

MCS51

ADD	A,Rn		0010 1nnn		Add
ADD	A,direct	0010 0101
ADD	A,@Ri		0010 011i
ADD	A,#data		0010 0100
ADDC	A,Rn		0011 1nnn		Add with Carry
ADDC	A,direct	0011 0101
ADDC	A,@Ri		0011 011i
ADDC	A,#data		0011 0100
SUBB	A,Ri		1001 1iii		Subtract with Borrow
SUBB	A,direct	1001 0101
SUBB	A,@Ri		1001 011i
SUBB	A,#data		1001 0100

INC	A		0000 0100		Increment
INC	Ri		0000 1iii
INC	direct		0000 0101
INC	@Ri		0000 011i
DEC	A		0001 0100		Decrement
DEC	Rn		0001 1iii
DEC	direct		0001 0101
DEC	@Ri		0001 011i

INC	DPTR		1010 0011	DPTR++

MUL	AB		1010 0100	A<7:0>,B<15:8> <- A * B
DIV	AB		1000 0100	A <- A /B


35.3.2 INTEGER LOGICAL INSTRUCTIONS

    Integer  Logical Instruction include all logical functions
operations such as
    - And
    - Or
    - Xor
    - Not

    and other  (as 2 operand, as 1 operand)

SPARC

SPARC format 3
+-----------------------+------------------------+
| 31..30	10      | 31..30	10	 |
| 29..25	rd	| 29..25	rd       |
| 24..19	op3	| 24..19	op3      |
| 18..14	rs1	| 18..14	rs1      |
| 13		0	| 13		1        |
| 12..5		---	| 12..0		simm13   |
| 4..0		rs2	|	                 |
+-----------------------+------------------------+

    Opcode		Op3		Operation
    and		00 0001		And
    andcc		01 0001		And and modify cc's
    andn		00 0101		And Not
    andncc		01 0101		And not and modify cc's
    or		00 0010		Inclusive Or
    orcc		01 0010		Inclusive Or and modify cc's
    orn		00 0110		Inclusive Or-Not
    orncc		01 0110		Inclusive Or-Not and modify cc's
    xor		00 0011		Exclusive Or
    xorcc		01 0011		Exclusive Or and modify cc's
    xnor		00 0111		Exclusive Or-Not
    xnorcc		01 0111		Exclusive Or-Not and modify cc's

op	reg(rs1),reg(rs2),reg(rd)
op	reg(rs1),simm13,reg(rd)

r[d] <-  r[rs1] _LOG_OP_ r[rs2]
r[d] <-  r[rs1] _LOG_OP_ sign_extend(simm13)

ALPHA

Alpha Operate Format
+-------------------------+------------------------+
| 31..26	Opcode	  | 31..26	Opcode	   |
| 25..21	Ra	  | 25..21	Ra	   |
| 20..16	Rb	  | 20..13	LIT        |
| 15..13	SBZ	  | 12		1          |
| 12		0	  | 11..5	Function   |
| 11..5		Function  | 4..0	Rc         |
| 4..0		Rc        |                        |
+-------------------------+------------------------+

Logical	Product
    AND	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    AND	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav AND Rbv

Logical	Product with Complement
    BIC	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    BIC	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav AND { NOT Rbv }

Logical Sum (OR)
    BIS	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    BIS	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav OR Rbv

Logical Equivalence (XORNOT)
    EQV	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    EQV	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav XOR { NOT Rbv }

Logical Sum with Complement
     ORNOT	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    ORNOT	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav OR { NOT Rbv }

Logical Difference
    XOR	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    XOR	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- Rav XOR Rbv

    AND	11.00
    BIC	11.08
    BIS	11.20
    EQV	11.48
    ORNOT	11.28
    XOR	11.40

Note:
    NOT can be performaed as ORNOT with zero (Ra = R31).

HP-PA

+---------------------------+
|	Len	Value       |
|	6	02          |		02
|	5	r2          |		r2
|	5	r1          |		r1
|	3	c	    |		c
|	1	f           |		f
|	6	xx          |		28
|	1	0	    |		0
|	5	t	    |		t
+---------------------------+

Command				xx
OR,cond		r1,r2,t		09	Inclusive OR

        rt <- r1 OR r2
        if (cond) PSW[N] <- 1

XOR,cond	r1,r2,t		0A	Exclusive OR

        rt <- r1 XOR r2
        if (cond) PSW[N] <- 1

AND,cond	r1,r2,t		08	And

        rt <- r1 AND r2
        if (cond) PSW[N] <- 1

ANDCM,cond	r1,r2,t		00	And Complement

        rt <- r1 AND (NOT r2)
        if (cond) PSW[N] <- 1

MIPS

+------------------------------+
|	Len	Value	       |
|	6	0              |
|	5	rs             |
|	5	rt	       |
|	5	rd             |
|	5	0              |
|	5	xx             |
+------------------------------+

Command				xx
AND	rd,rs,rt		10 0100		And
    rd <- rs AND rt

NOR	rd,rs,rt		10 0111		Not or
    rd <- rs NOR rt

OR	rd,rs,rt		10 0101		Or
    rd <- rs OR  rt

XOR	rd,rs,rt		10 0110		Xor
    rd <- rs XOR rt

+------------------------+
|	Len	Value    |
|	6	xx	 |
| 	5	rs       |
|	5	rt       |
|	16	immm     |
+------------------------+

Command			xx
ANDI	rt,rs,imm	00 1100		And Immediate
    rt <- rs AND zero_ext(immediate)

ORI	rt,rs,imm	00 1101		Or Immediate
    rt <- rs OR  zero_ext(immediate)

XORI	rt,rs,imm	00 1110		Xor Immediate
    rt <- rs XOR zero_ext(imm)

PowerPC

0..5	opcode1
6..10	S
11..15	A
16..20	B
21..30	opcode2
31	Rc

            Rc	opcode1.opcode2
and	rA,rS,rB	0	31.28			And
and.	rA,rS,rB	1

    rA <- rS AND rB

andc	rA,rS,rB	0	31.60			And with Complement
andc.	rA,rS,rB	1

    rA <- rS AND (NOT rB)

eqv	rA,rS,rB	0	31.284			Equivalent
eqv.	rA,rS,rB	1

    rA <- rS EQV rB

nor	rA,rS,rB	0	31.124			NOR
nor.	rA,rS,rB	1

    rA <- NOT (rS OR rB )

or	rA,rS,rB	0	31.444			OR
or.	rA,rS,rB	1

    rA <- rS OR rB

orc	rA,rS,rB	0	31.412			OR with Complement
orc.	rA,rS,rB	1

    rA <- rS OR (NOT rB)

xor	rA,rS,rB	0	31.316			XOR
xor.	rA,rS,rB	1

    rA <- rS XOR rB

        // ----------------------------------------------------------

0..5	opcode1
6..10	S
11..15	A
16..31	SIMM

            opcode1
andi.	rA,rS,UIMM	28		AND Immediate

    rA <- rS AND zero_ext(UIMM)

andis.	rA,rS,UIMM	29		AND Immediate Shifted

    rA <- rS AND zero_ext(UIMM << 16)

ori	rA,rS,UIMM	24		OR Immediate

    rA <- rS OR zero_ext(UIMM)

oris	rA,rS,UIMM	25		OR Immediate Shifted

    rA <- rS OR zero_ext(UIMM << 16)

xori	rA,rS,UIMM	26		XOR Immeditae

    rA <- rS  XOR zero_ext(UIMM)

xoris	rA,rS,UIMM	27		XOR Immediate Shifted

    rA <- rS XOR zero_ext(UIMM << 16)

Note:
    nop code	is ori 0,0,0

68K

Code			Size	Mnemonic		Description
1101nnn0ss<-EA->	B,W,L	AND	,Dn		 AND Dn -> Dn
1101nnn1ss<-EA->	B,W,L	AND	Dn,		Dn AND  ->
00000010ss<-EA->	B,W,L	ANDI	#im,	#im AND  ->

1011nnn1ss<-EA->	B,W,L	EOR	Dn,		Dn XOR  ->
00001010ss<-EA->	B,W,L	EORI	#im,	#im XOR  ->

01000110ss<-EA->	B,W,L	NOT			NOT  ->

1000nnn0ss<-EA->	B,W,L	OR	,Dn		 OR Dn -> Dn
1000nnn1ss<-EA->	B,W,L	OR	Dn,		Dn OR  ->
00000000ss<-EA->	B,W,L	ORI	#im,	#im OR  ->

Z80

Operation		Description			Code
AND	r		A <- A AND r			A0+r
AND	n		A <- A AND n			E6 n
AND	(ii+n)		A <- A AND (ii+n)		ii A6 n

CPL			A <- A XOR 255  		2F
            (i.e. NOT A)

OR	r		A <- A OR r			B0+r
OR	n		A <- A OR n			F6 n
OR	(ii+n)		A <- A OR (ii+n)		ii B6 n

XOR	r		A <- A XOR r			A8+r
XOR	n		A <- A XOR n			EE n
XOR	(ii+n)		A <- A XOR (ii+n)		ii AE n

X86

    (Logical AND) =================
AND	AL,imm8			24 	ib
AND	AX,imm16		25 	iw
AND	EAX,imm32		25	id
AND	r/m8,imm8		80/4	ib
AND	r/m16,imm16		81/4	iw
AND	r/m32,imm32		81/4	id
AND	r/m16,imm8		83/4	iw
AND	r/m32,imm8		83/4	iw
AND	r/m8,r8			20/r
AND	r/m16,r16		21/r
AND	r/m32,r32		21/r
AND	r8,r/m8			22/r
AND	r16,r/m16		23/r
AND	r32,r/m32		23/r

    DEST <- DEST AND SRC

    (One's complement Negation) =====
NOT	r/m8			F6 /2
NOT	r/m16			F7 /2
NOT	r/m32			F7 /2

    DEST <- NOT DEST

    (Logical Inclusive OR) ===============
OR	AL,imm8			0C 	ib
OR	AX,imm16		0D 	iw
OR	EAX,imm32		0D	id
OR	r/m8,imm8		80/1	ib
OR	r/m16,imm16		81/1	iw
OR	r/m32,imm32		81/1	id
OR	r/m16,imm8		83/1	iw
OR	r/m32,imm8		83/1	iw
OR	r/m8,r8			08/r
OR	r/m16,r16		09/r
OR	r/m32,r32		09/r
OR	r8,r/m8			0A/r
OR	r16,r/m16		0B/r
OR	r32,r/m32		0B/r

    DEST <- DEST OR SRC

    (Logical Exclusive OR) ===============
XOR	AL,imm8			34 	ib
XOR	AX,imm16		35 	iw
XOR	EAX,imm32		35	id
XOR	r/m8,imm8		80/6	ib
XOR	r/m16,imm16		81/6	iw
XOR	r/m32,imm32		81/6	id
XOR	r/m16,imm8		83/6	iw
XOR	r/m32,imm8		83/6	iw
XOR	r/m8,r8			30/r
XOR	r/m16,r16		31/r
XOR	r/m32,r32		31/r
XOR	r8,r/m8			32/r
XOR	r16,r/m16		33/r
XOR	r32,r/m32		33/r

    DEST <- DEST XOR SRC

IA64

Format  A1	       Format A3
------------	+     ------------
40..37	8	      	40..37	8
36	--		36	S
35..34	X2a		35..34	X2a
33	Ve		33	Ve
32..29	X4		32..29	X4
28..27	X2b		28..27	X2b
26..20	R3		26..20	R3
19..13	R2		19..13	Imm7b
12..6	R1		12..6	R1
5..0	QP		5..0	QP
------------	+     --------------

and		r1=r2,r3	A1	8.0.0.3.0
andcm		r1=r2,r3	A1	8.0.0.3.1
or		r1=r2,r3	A1	8.0.0.3.2
xor		r1=r2,r3	A1	8.0.0.3.3

and		r1=imm8,r3	A3	8.0.0.b.0
andcm		r1=imm8,r3	A3	8.0.0.b.1
or		r1=imm8,r3	A3	8.0.0.b.2
xor		r1=imm8,r3	A3	8.0.0.b.3

JVM

IAND		7Eh			(a AND b)	32
IOR		80h			(a OR  b)	32
IXOR		82h			(a XOR b)	32

LAND		7Fh			(a AND b)	64
LOR		81h			(a OR  b)	64
LXOR		83h			(a XOR b)	64

MCS51

ANL	A,Rn		0101 1nnn			Logical AND
ANL	A,direct	0101 0101 [direct]
ANL	A,@Ri		0101 011i
ANL	A,#data		0101 0100 [data]
ANL	direct,A	0101 0010 [direct]
ANL	direct,#data	0101 0011 [direct] [data]

ORL	A,Rn		0100 1nnn			Logical OR
ORL	A,direct	0100 0101 [direct]
ORL	A,@Ri		0100 011i
ORL	A,#data		0100 0100 [data]
ORL	direct,A	0100 0010 [direct]
ORL	direct,#data	0100 0011 [direct] [data]

XRL	A,Rn		0110 1nnn			Logical XOR
XRL	A,direct	0110 0101 [direct]
XRL	A,@Ri		0110 011i
XRL	A,#data		0110 0100 [data]
XRL	direct,A	0110 0010 [direct]
XRL	direct,#data	0110 0011 [direct] [data]

CPL	A		1111 0100			Logical Complement

Note:	MCS51 have commands which perform logic operations with bits.


35.3.3 INTEGER SHIFT/ROTATES INSTRUCTIONS

    Shift and Rotates Instructions Include

    Shifts:
        - Arithmetical Shift	(Left/Right)
        - Logical      Shift	(Left/Right)
    Rotate:
        - Simple		(Left/Right)
        - with Carry Flag	(Left/Right)

    Also exist some other complex rotates and registers order
swaps.

SPARC

SPARC format 3
+-----------------------+------------------------+------------------------+
| 31..30	10      | 31..30	10	 |  31..30	10        |
| 29..25	rd	| 29..25	rd       |  29..25	rd        |
| 24..19	op3	| 24..19	op3      |  24..19	op3	  |
| 18..14	rs1	| 18..14	rs1      |  18..14	rs1	  |
| 13		0	| 13		1        |  13		1         |
| 12		x	| 12		x=0	 |  12		x=1	  |
| 11..5		---	| 11..5		----     |  11..6	---	  |
| 4..0		rs2	| 4..0		shcnt32  |  5..0	shcnt64   |
+-----------------------+------------------------+------------------------+

    x	Shift count
    0	bits 4..0 of r[rs2]
    1	bits 5..0 of r[rs2]

    Opcode		Op3	  x	Operation
    sll		10 0101	  0	Shift Left Logical 32 bit
    srl		10 0110   0	Shift Right Logical  32 bit
    sra		10 0111   0	Shift Right Arithmetic 32 bit
    sllx		10 0101   1	Shift Left Logical 64 bit
    srlx		10 0110	  1	Shift Right Logical 64 bit
    srax		10 0111	  1	Shift Right Arithmetic 64 bit

Note:
    sra	rs1,0,rd	can be used for convert 32-bit value
to 64 bit with sign extend.
    srl	rs1,0,rd	used for clear upper 32-bit of r[rd]

op	reg(rs1),reg(rs2),reg(rd)
op	reg(rs1),shcnt32/64,reg(rd)

r[d] <-  r[rs1] _SHIFT_ low_bits(r[rs2])
r[d] <-  r[rs1] _SHIFT_ shcnt32/64

ALPHA

Alpha Operate Format
+-------------------------+------------------------+
| 31..26	Opcode	  | 31..26	Opcode	   |
| 25..21	Ra	  | 25..21	Ra	   |
| 20..16	Rb	  | 20..13	LIT        |
| 15..13	SBZ	  | 12		1          |
| 12		0	  | 11..5	Function   |
| 11..5		Function  | 4..0	Rc         |
| 4..0		Rc        |                        |
+-------------------------+------------------------+

Shift	Logical Left
    SLL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    SLL	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- LEFT_SHIFT(Rav, Rbv<5:0>)

Shift	Logical Right
    SRL	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    SRL	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- RIGHT_SHIFT(Rav, Rbv<5:0>)

Shift	Arithmetic
    SRA	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    SRA	Ra.rq,#b.ib,Rc.wq	!Operate Format

    Rc <- ARITH_RIGHT_SHIFT(Rav, Rbv<5:0>)

    SLL	12.39
    SRL	12.34
    SRA	12.3C

HP-PA

Instruction Format:
+---------------------------+
|	Len	Value       |
|	6	34          |
|	5	r2          |
|	5	r1          |
|	3	c	    |
|	3	xx          |
|	5	0           |
|	5	t	    |
+---------------------------+

Command				xx
VSHD,cond	r1,r2,t		0	Variable Shift Double

    GR[t] <- RSHIFT(cat(GR[r1]{1..31},GR[r2]),CR[11]){32..63}
    if (cond) PSW[N] <- 1

VEXTRU,cond	r,len,t		4	Variable Extract Unsigned

    shct <- 1 + CR[11];
    tmp  <- lshift(zero_ext_64(GR[r],32),shct){0..31}
    GR[t] <- zero_ext(tmp{32-len..31},len);
    if (cond) PSW[N] <- 1

VEXTRS,cond	r,len,t		5	Variable Extract Signed

    shct <- 1 + CR[11];
    tmp  <- lshift(zero_ext_64(GR[r],32),shct){0..31}
    GR[t] <- sign_ext(tmp{32-len..31},len);
    if (cond) PSW[N] <- 1

Instruction Format:
+---------------------------+
|	Len	Value       |
|	6	34          |
|	5	r2          |
|	5	r1          |
|	3	c	    |
|	3	xx          |
|	5	p           |
|	5	t	    |
+---------------------------+

Command				xx
SHD,cond	r1,r2,p,t	2	Shift Double

    GR[t] <- RSHIFT(cat(GR[r1]{1..31},GR[r2]),p){32..63}
    if (cond) PSW[N] <- 1

EXTRU,cond	r,p,len,t	6	Extract Unsigned

    tmp <- LSHIFT(zero_ext_64(GR[r],32),(1+p)) {0..31}
    GR[t] <- zero_ext(tmp{32-len..31},len);
    if (cond) PSW[N] <- 1

EXTRS,cond	r,p,len,t	7	Extract Signed

    tmp <- LSHIFT(zero_ext_64(GR[r],32),(1+p)) {0..31}
    GR[t] <- sign_ext(tmp{32-len..31},len);
    if (cond) PSW[N] <- 1

Note:
    There are lot of near instructions in HP-PA architecture..
VDEP/DEP/VDEPI/DEPI/ZVDEP/ZDEP/ZVDEPI/ZDEPI

MIPS

+------------------------------+
|	Len	Value	       |
|	6	0              |
|	5	0              |
|	5	rt             |
|	5	rd             |
|	5	sa             |
|	5	xx             |
+------------------------------+

Command			xx
DSLL	rd,rt,sa	11 1000		Doubleword Shift Left Logical
        rd <- rt << sa		(MIPS III)

DSLL32	rd,rt,sa	11 1100		Doubleword Shift Left Logical plus 32
        rd <- rt << (sa+32)	(MIPS III)

DSRA	rd,rt,sa	11 1011		Doubleword Shift Right Arithmetic
        rd <- rt >>> sa		(MIPS III)

DSRA32	rd,rt,sa	11 1011		Doubleword Shift Right Arithmetic
        rd <- rt >>> (sa +32)	plus 32 (MIPS III)

DSRL	rd,rt,sa	11 1010		Doubleword Shift Right Logical
        rd <- rt >> sa		(MIPS III)

DSRL32	rd,rt,sa	11 1110		Doubleword Shift Right Logical
        rd <- rt >> (sa+32)	plus 32 (MIPS III)

SLL	rd,rt,sa	00 0000  	Shift word left Logical
        rd <- rt << sa		(32-bit parts)

SRA	rd,rt,sa	00 0011		Shift word Right Arithmetic
        rd <- rt >>> sa		(32-bit)

SRL	rd,rs,sa	00 0010		Shift Word Right Logical
        rd <- rt >> sa		(32-bit)

+------------------------------+
|	Len	Value	       |
|	6	0              |
|	5	rs             |
|	5	rt             |
|	5	rd             |
|	5	0              |
|	5	xx             |
+------------------------------+

Command			xx
DSLLV	rd,rt,rs	01 0100		Doubleword Shift Left Logical Variable
        rd <- rt << rs		(MIPS III)

DSRAV	rd,rt,rs	01 0111		Doubleword Shift Right Arithmetic
        rd <- rt >>> rs		Variable (MIPS III)

DSRLV	rd,rt,rs	01 0110		Doubleword Shift Right Logical Variable
        rd <- rt >> rs		(MIPS III)

SLLV	rd,rt,rs	00 0100		Shift Word Left Logical Variable
        rd <- rt << rs		(32bit)

SRAV	rd,rt,rs	00 0111		Shift Word Right Arithmetic Variable
        rd <- rt >>> rs		(32bit)

SRLV	rd,rt,rs	00 0110		Shift Word Right Logical Variable
        rd <- rt >> rs		(32-bit)

Note:	32bit operations perform only on low 32-bit parts of registers!!

PowerPC

0..5	opcode1
6..10	S
11..15	A
16..20	SH
21..30	opcode2
31	Rc

            Rc	opcode

slw	rA,rS,rB	0	31.24		Shift Left Word
slw.	rA,rS,rB	1

        rA <- ROTL(rS,rB[27-31])

sraw	rA,rS,rB	0	31.792		Shift Right Algebraic Word
sraw.	rA,rS,rB	1

        rA <- ROTL(rS,32- rB[27-31])

srw	rA,rS,rB	0	31.536		Shift Right Word
srw.	rA,rS,rB	1

        rA <- ROTL(rS,32-rB[27-31])

0..5	opcode1
6..10	S
11..15	A
16..20	SH
21..30	opcode2
31	Rc

srawi	rA,rS,SH	0	31.824
srawi.	rA,rS,SH	1

    rA <- ROTL(rS,32-SH)

Note:	Exist complex Rotates with Mask Insert:

rlwimi/rlwimi.		- Rotate Left Word Immediate then Mask Insert
rlwinm/rlwinm.		- Rotate Left Word Immediate then AND with Mask
rlwnm/rlwnm.		- Rotate Left Word then AND with Mask

68K

Code			Size	Mnemonic		Description
            (Shift Arithmetic Left)
1110xxx1ss000yyy	B,W,L	ASL	#x,Dy		Dy << #x  -> Dy
1110xxx1ss100yyy	B,W,L	ASL	Dx,Dy		Du << Dx  -> Dy
1110000111<-EA->	W	ASL

            C <----+---- SRC <--- 0
            X <---/

            (Shift Arithmetic Right)
1110xxx0ss000yyy	B,W,L	ASR	#x,Dy		Dy >>> #x  -> Dy
1110xxx0ss100yyy	B,W,L	ASR	Dx,Dy		Du >>> Dx  -> Dy
1110000011<-EA->	W	ASR

            +---> SRC -------+-----> C
            |    |           |
            +----+           +-----> X
                high bit

            (Shift Logical Left)
1110xxx1ss001yyy	B,W,L	LSL	#x,Dy		Dy << #x  -> Dy
1110xxx1ss101yyy	B,W,L	LSL	Dx,Dy		Dy << Dx  -> Dy
1110001111<-EA->	W	LSL

            C <----+---- SRC <--- 0
            X <---/

            (SHift Logical Right)
1110xxx0ss001yyy	B,W,L	LSR	#x,Dy		Dy >> #x -> Dy
1110xxx0ss101yyy	B,W,L	LSR	Dx,Dy		Dy >> Dx -> Dy
1110001011<-EA->	W	LSR

            0  ---> SRC ----+-----> C
                            |
                            +-----> X

1110xxx1ss011yyy	B,W,L	ROL	#x,Dy
1110xxx1ss111yyy	B,W,L	ROL	Dx,Dy
1110011111<-EA->	W	ROL

            C <---+-- SRC <----+
                   |            |
                  +----------->+

1110xxx0ss011yyy	B,W,L	ROR	#x,Dy
1110xxx0ss111yyy	B,W,L	ROR	Dx,Dy
1110011011<-EA->	W	ROR

            +--->  SRC --+---> C
            |            |
            +<-----------+
Note: In 68K exist 2 additional operaions ROXL and ROXR it's like
Rotates throught carry.

1110xxx1ss010yyy	B,W,L	ROXL	#x,Dn
1110xxx1ss110yyy	B,W,L	ROXL	Dx,Dy
1110010111<-EA->	W	ROXL

            C <----------+---- SRC <----+
                     |		    |
                  X <----+		    |
                  |			    |
                  +--------------------->+

1110xxx0ss010yyy	B,W,L	ROXR	#x,Dy
1110xxx0ss110yyy	B,W,L	ROXR	Dx,Dy
1110010011<-EA->	W	ROXR

             +---->  SRC -----------+---------> C
             |                      |
             +<--------- X <--------+

Z80

Operation		Description			Code
RL	r		Rotate Left			CB 10+r
RL	(ii+n)						ii CB n 16

            +<--- Cy <--- r <--+
            |		   |
            +----------------->+

RLC	r		Rotate Left w/o	 carry		CB 00+r
RLC	(ii+n) 						ii CB n 06

            Cy <---+--- r <----+
                   |	   |
                   +---------->+

RR	r		Rotate Right			CB 18+r
RR	(ii+n)						ii CB n 1E

            +---> Cy ---> r -->+
            |		   |
            +<-----------------+

RRC	r		Rotate Right w/o carry		CB 08+r
RRC	(ii+n)						ii CB n 0E

            Cy <---+---> r --->+
                   |	   |
                   +<----------+

SLA	r		Shift Left Arithmetic		CB 20+r
SLA	(ii+n)						ii CB n 26

            Cy <--- r <--- 0

SLI	r		Shift Left Logical		CB 30+r
SLI	(ii+n)						ii CB n 36

            Cy <--- r <---- 0		(UNDOCUMNENT)

SRA	r		Shift Right Atithmetic		CB 28+r
SRA	(ii+n)						ii CB n 2E

            +---> r  ------> Cy
            |     |
            +<----+
               high bit

SRL	r		Shift Right Logical		CB 38+r
SRL	(ii+n)						ii CB n 3E

            0 ---->  r -----> Cy

Note:
    Also exist RLD, RRD

X86

    (Rotate through carry Right)
RCR	r/m8,1			D0/3
RCR	r/m8,CL			D2/3
RCR	r/m8,imm8		C0/3    ib
RCR	r/m16,1			D1/3
RCR	r/m16,CL		D3/3
RCR	r/m16,imm8		C1/3	ib
RCR	r/m32,1			D1/3
RCR	r/m32,CL		D3/3
RCR	r/m32,imm8		C1/3	ib

    +---> SRC ---> CF ---+
    |                    |
    +<-------------------+

    (Rotate throught carry Left)
RCL	r/m8,1			D0/2
RCL	r/m8,CL			D2/2
RCL	r/m8,imm8		C0/2    ib
RCL	r/m16,1			D1/2
RCL	r/m16,CL		D3/2
RCL	r/m16,imm8		C1/2	ib
RCL	r/m32,1			D1/2
RCL	r/m32,CL		D3/2
RCL	r/m32,imm8		C1/2	ib

    +<--- SRC <--- CF <--+
    |                    |
    +------------------->+

    (Rotate Right)
ROR	r/m8,1			D0/1
ROR	r/m8,CL			D2/1
ROR	r/m8,imm8		C0/1    ib
ROR	r/m16,1			D1/1
ROR	r/m16,CL		D3/1
ROR	r/m16,imm8		C1/1	ib
ROR	r/m32,1			D1/1
ROR	r/m32,CL		D3/1
ROR	r/m32,imm8		C1/1	ib

      +---> SRC --->+---> CF
      |             |
          +<------------+

    (Rotate Left)
ROL	r/m8,1			D0/0
ROL	r/m8,CL			D2/0
ROL	r/m8,imm8		C0/0    ib
ROL	r/m16,1			D1/0
ROL	r/m16,CL		D3/0
ROL	r/m16,imm8		C1/0	ib
ROL	r/m32,1			D1/0
ROL	r/m32,CL		D3/0
ROL	r/m32,imm8		C1/0	ib

      +---- SRC <---+---> CF
      |             |
          +------------>+

    (SHift Right Logical)
SHR	r/m8,1			D0/5
SHR	r/m8,CL			D2/5
SHR	r/m8,imm8		C0/5    ib
SHR	r/m16,1			D1/5
SHR	r/m16,CL		D3/5
SHR	r/m16,imm8		C1/5	ib
SHR	r/m32,1			D1/5
SHR	r/m32,CL		D3/5
SHR	r/m32,imm8		C1/5	ib

    0 >--> SRC ----> CF

    (Shift Left Logical)
SHL	r/m8,1			D0/4
SHL	r/m8,CL			D2/4
SHL	r/m8,imm8		C0/4    ib
SHL	r/m16,1			D1/4
SHL	r/m16,CL		D3/4
SHL	r/m16,imm8		C1/4	ib
SHL	r/m32,1			D1/4
SHL	r/m32,CL		D3/4
SHL	r/m32,imm8		C1/4	ib

    CF <--- SRC  <---< 0

    (Shift Right Arithmetical)
SAR	r/m8,1			D0/7
SAR	r/m8,CL			D2/7
SAR	r/m8,imm8		C0/7    ib
SAR	r/m16,1			D1/7
SAR	r/m16,CL		D3/7
SAR	r/m16,imm8		C1/7	ib
SAR	r/m32,1			D1/7
SAR	r/m32,CL		D3/7
SAR	r/m32,imm8		C1/7	ib

    +---> SRC ----> CF
    |    |
        +<---+
       high bit

    (Shift Left Arithmetical)
SAL	r/m8,1			D0/4
SAL	r/m8,CL			D2/4
SAL	r/m8,imm8		C0/4    ib
SAL	r/m16,1			D1/4
SAL	r/m16,CL		D3/4
SAL	r/m16,imm8		C1/4	ib
SAL	r/m32,1			D1/4
SAL	r/m32,CL		D3/4
SAL	r/m32,imm8		C1/4	ib

Note:	SAL and SHL are synonims

    (Double Precension Shift Left)
SHLD	r/m16,r16,imm8		0F A4
SHLD	r/m32,r32,imm8		0F A4
SHLD	r/m16,r16,CL		0F A5
SHLD	r/m32,r32,CL		0F A5

    CF <--- r <--- r/m <--- 0

    (Double Precension Shift Right)
SHRD	r/m16,r16,imm8		0F AC
SHRD	r/m32,r32,imm8		0F AC
SHRD	r/m16,r16,CL		0F AD
SHRD	r/m32,r32,CL		0F AD

    0 ---> r/m ---> r -->  CF

IA64

Format I5, I7
-----------
40..37	7
36	Za
35..34	X2a
33	Zb
32	Ve
31..30	X2c		Opcode:	7.Za.Zb.Ve.X2a.X2b.X2c
29..28	X2b
27	--
26..20	r3
19..13	r2
12..6	r1
5..0	qp
------------

Format	I10
------------
40..37	5
36	--
35..34	X2
33	X
32..27	count6d		Opcode: 5.x2.x.
26..20	r3
19..13	r2
12..6	r1
5..0	qp
------------

shr		r1=r3,r2	I5	7.1.1.0.0.2.0	Shift Right Signed
shr.u		r1=r3,r2	I5	7.1.1.0.0.0.0	Shift Right Unsigned
shl		r1=r2,r3	I7	7.1.1.0.0.0.1	Shift Left

shrp		r1=r2,r3,count6	I10	5.3.0		Shift Right Pair

Note: For Smaller Size shifts use next instructions
    PSHR2/PSHR2.U/PSHL2	r1=r3,r2	r1=r3,count5
    PSHR4/PSHR4.U/PSHL4	r1=r3,r2	r1=r3,count5

Note: For complex operations possibly usage of more complex ops:

    EXTR/EXTR/U	r1=r3,pos6,len6			Extract
    DEP.Z		r1=r2,pos6,len6 		Zero and Deposit
            r1=imm8,pos6,len6
    DEP		r1=imm1,r3,pos6,len6		Deposite
            r1=r2,r3,pos6,len4

// ----------------------------------------------------------------------

JVM

ISHL		78h			(a << b)	32
ISHR		7Ah			(a >> b)	32
IUSHR		7Ch			(a >>> b)	32

LSHL		79h			(a << b)	64
LSHR		7Bh			(a >> b)	64
LUSHR		7Dh			(a >>> b)	64

MCS51

RL	A		0010 0011		Rotate Accumulator Left

        (An+1) <- (An)
        (A0)   <- (A7)

RR	A		0000 0011		Rotate Accumulator Right

        (An)   <- (An+1)
        (A7)   <- (A0)
RLC	A		0011 0011		Rotate Accumulator Left
                        (throught Cy)

        (An+1) <- (An)
        (A0)   <- C
        C      <- (A7)

RRC	A		0001 0011		Rotate Accumulator Right
                        (throught Cy)
        (An)   <- (An+1)
        (A7)   <- C
        C      <- A0


35.3.4 INTEGER LOAD/STORE INSTRUCTIONS

o	Integer Load/Store
o	Load Immediate Values to Registers
o	Semaphore operations
o	Prefetches Hints	(NOT YET)

Note:	Move  databetween Registers see in data conversion section.

SPARC

SPARC format 3
+-----------------------+------------------------+
| 31..30	11      | 31..30	11	 |
| 29..25	rd	| 29..25	rd       |
| 24..19	op3	| 24..19	op3      |
| 18..14	rs1	| 18..14	rs1      |
| 13		0	| 13		1        |
| 12..5		---	| 12..0		simm13   |
| 4..0		rs2	|	                 |
+-----------------------+------------------------+

    Opcode		Op3		Operation
    ldsb		00 0101		Load Signed Byte
    ldsh		00 1010		Load Signed Halfword
    ldsw		00 1000		Load Signed Word
    ldub		00 0001		Load Unsigned Byte
    lduh		00 0010		Load Unsigned Halfword
    lduw		00 0000		Load Unsigned word
    ldx		00 1011		Load Extended Word
    ldd		00 0011		Load Doubleword

    All Data Must be aligned..

ldXX	[address],reg(rd)

    address = r[rs1]+r[rs2]			// Direct
    address = r[rs1]+sign_ext(simm13)	// Immediate
    r[rd] <- memory[address]

Aliases:
    lduw		ld

    Opcode		Op3		Operation
    ldstub		00 1101		Load-Store Unsigned Byte

ldstub	[address],reg(rd)

    address = r[rs1]+r[rs2]			// Direct
    address = r[rs1]+sign_ext(simm13)	// Immediate
    r[rd] <- memory[address]
    memory[address] <- 0xffh

    Opcode		Op3		Operation
    stb		00 0101		Store Byte
    sth		00 0110		Store Halfword
    stw		00 0100		Store Word
    stx		00 1110		Store Extended Word
    std		00 0111		Store Doubleword

stXX	reg(rd),[address]

Aliases:
    stb		stub	stsb
    sth		stuh	stsh
    stw		stuw	stsw

ALPHA

Alpha Memory Format
+-----------------------+
| 31..26	Opcode	|
| 25..21	Ra	|
| 20..16	Rb	|
| 15..0		mdisp	|
+-----------------------+

Load	Address
    LDA	Ra.wq,disp.ab(Rb.ab)	!Memory Frmat
    LDAH	Ra.wq,disp.ab(Rb.ab)	!Memory Frmat

    Ra <- Rbv + SEXT(disp)		!LDA
    Ra <- Rbv + SEXT(disp << 16)	!LDAH

    LDA	08
    LDAH	09

Load Memory Data into Integer Register

    LDL	Ra.wq,disp.ab(Rb.ab)	!Memory Format
    LDQ	Ra.wq,disp.ab(Rb.ab)	!Memory Format

    va <- { Rbv + SEXT(disp) }
    Ra <- SEXT((va)<31:0>)		! LDL
    Ra <- (va)<63:0>		! LDQ

    LDL	28
    LDQ	29

Load Unaligned Memory Data into Integer Register

    LDQ_U	Ra.wq,disp.ab(Rb.ab)	!Memory Format

    va <- {{Rbv + SEXT(disp)} AND NOT 7 }
    Ra <- (va)<63:0>

    LDQ_U	0B

Store Integer Register Data into Memory

    STL	Ra.rq,disp.ab(Rb.ab)	!Memory Format

    va <- { Rbv + SEXT(disp) }
    (va)<31:0> <- Rav<31:0>		!STL
    (va)	   <- Rav		!STQ

    STL	2C
    STQ	2D

Store Unaligned Integer Register Data into Memory

    STQ_U	Ra.rq,disp.ab(Rb.ab)	!Memory Format

    va <- {{Rbv + SEXT(disp)} AND NOT 7 }
    (va)<63:0> <- Rav

    STQ_U	0F

Load Memory Data into Register Locked

    LDL_L	Ra.wq,disp.ab(Rb.ab)	!Memory Format
    LDQ_L	Ra.wq,disp.ab(Rb.ab)	!Memory Format

    va <- { Rbv + SEXT(disp) }
    lock_flag <- 1
    locked_physical_address <- PHYSICAL_ADDRESS(va)
    Ra <- SEXT(va)<31:0>			! LDL_L
    Ra <- va<63:0>				! LDQ_L

    LDL_L	2A
    LDQ_L	2B

Store Integer Registers Data into Memory Conditional

    STL_C	Ra.mq,disp.ab(Rb.ab)	!Memory format
    STQ_C	Ra.mq,disp.ab(Rb.ab)	!Memory format

    va <- { Rbv + SEXT(disp) }
    if lock_flag EQ 1 THEN
        (va)<31:0> <- Rav<31:0>		! STL_C
        (va) <- Rav			! STQ_C
    Ra <- lock_flag
    lock_flag <- 0

    STL_C	2E
    STQ_C	2F

Note:
    For load data values low that dword, need to use next
commands:

EXTBL/EXTWL/EXTLL/EXTQL		Extract xxx low
EXTWH/EXTLH/EXTQH		Extract xxx high

    For store data values which low that word need to use
next commands

INSBL/INSWL/INSLL/INSQL		Insert  xxx low
INSWH/INSLH/INSQH		Insert  xxx high

ZAP				Zero bytes

On Extended Alpha Architecture possible usage of

SEXTB/SEXTW			Sign Extend
LDBU/LDWU			Load Unsignef byte/word

For more info refer to type conversion section.

HP-PA

    Load			 Store
+---------------------------+-------------------+
|	Len	Value       | 	Len	Value	|
|	6	opcode      |			|
|	5	b           |			|
|	5	t           |	5	r	|
|	2	s	    |			|
|	14	im14        |			|
+---------------------------+-------------------+

Command				opcode
LDW		d(s,b),t	12	Load Word
LDH		d(s,b),t	11	Load Halfword
LDB		d(s,b),t	10	Load Byte

LDWM		d(s,b),t	13	Load word and Modify

STW		r,d(s,b)	1A	Store Word
STH		r,d(s,b)	19	Store Halfword
STB		r,d(s,b)	18	Store Byte

STWM		r,d(s,b)	1B	Store Word and Modify

+---------------------------+
    Len	Value
    6	opcode1
    5	b
    5	x
    2	s
    1	u
    1	opcode2
    2	cc
    4	opcode3
    1	m
    5	t
-------------------------------

LDWX,cmplt,cc	x(s,b),t	03.0.2	Load Word Indexed
LDHW,cmplt,cc	x(s,b),t	03.0.1	Load Halfword Indexed
LDBX,cmplt,cc	x(s,b),t	03.0.0	Load Byte Indexed
LDWAX,cmplt,cc	x(b),t		03.0.6	Load Word Absolute Indexed (s=0)
LDCWX,cmplt,cc	x(s,b),t	03.0.7	Load and Clear word Indexed

    Load			   Store
+---------------------------+--------------------+
    Len	Value
    6	opcode1
    5	b
    5	im5		5	r
    2	s
    1	a
    1	opcode2
    2	cc
    4	opcode3
    1	m
    5	t		5	im5
--------------------------------------------------+

LDWS,cmplt,cc	d(s,b),t	03.1.2	Load Word Short
LDHS,cmplt,cc	d(s,b),t	03.1.1	Load Halfword Short
LDBS,cmplt,cc	d(s,b),t	03.1.0	Load Byte SHort
LDWAS,cmplt,cc	d(b),t		03.1.6	Load Word Absolute Short
LDCWS,cmplt,cc	d(s,b),t	03.1.7	Load and Clear word short

STWS,cmplt,cc	r,d(s,b)	03.1.A	Store word short
STHS,cmplt,cc	r,d(s,b)	03.1.9	Store Halfword short
STBS,cmplt,cc	r,d(s,b)	03.1.8	Store Byte short
STWAS,cmplt,cc	r,d(b)		03.1.E	Store Word Absolute Short
STBYS,cmplt,cc	r,d(s,b)	03.1.C	Store Bytes Short

Load Immediate:

LDO/LDIL/ADDIL

MIPS

+------------------------------+
|	Len	Value
|	6	opcode
|	5	base
|	5	rt
|	16	offset
+------------------------------+

Command				xx	MIPS
LB	rt,offset(base)		10 0000	  I	Load Byte
LBU	rt,offset(base)		10 0100	  I	Load Byte Unsigned
LD	rt,offset(base)		11 0111	 III	Load Doubleword
LDL	rt,offset(base)		01 1010	 III	Load Doubleword Left
LDR	rt,offset(base)		01 1011	 III	Load Doubleword Right
LH	rt,offset(base)		10 0001	  I	Load Halfword
LHU	rt,offset(base)		10 0101	  I	Load Halfword Unsigned
LW	rt,offset(base)		10 0011	  I	Load Word
LWL	rt,offset(base)		10 0010	  I     Load Word Left
LWR	rt,offset(base)		10 0110	  I     Load Word Right
LWU	rt,offset(base)		10 0111	 III	Load Word Unsigned

SB	rt,offset(base)		10 1000	  I	Store Byte
SD	rt,offset(base)		11 1111	  III	Store Doubleword
SDL	rt,offset(base)		10 1100	  III	Store Doubleword Left
SDR	rt,offset(base)		10 1101	  III	Store Doubleword Right
SH	rt,offset(base)		10 1001	  I	Store Halfword
SW	rt,offset(base)		10 1011	  I	Store Word
SWL	rt,offset(base)		10 1010	  I	Store Word Left
SWR	rt,offset(base)		10 1110	  I	Store Word Right

(Semaphore operations)
LL	rt,offset(base)		11 0000	  II	Load Linked Word
LLD	rt,offset(base)		11 0100	  III	Load Linked Doubleword
SC	rt,offset(base)		11 1000	  II	Store Conditional Word
SCD	rt,offset(base)		11 1100	  III	Store Conditional Doubleword

(Misc)
PREFETCH

(Immediate Load)

LUI	- Load Upper Immediate

PowerPC

---------------
0..5	opcode1
6..10	D
11..15	A
16..31	d
---------------

lbz	rD,d(rA)	34	Load Byte and Zero
lbzu	rD,d(rA)	35	Load Byte and Zero with Update
lha	rD,d(rA)	42	Load Halfword Algebraic
lhau	rD,d(rA)	43	Load Halfword Algebraic with Update
lhz	rD,d(rA)	40	Load Halfword and Zero
lhzu	rD,d(rA)	41	Load Halfword and Zero with Update
lmw	rD,d(rA)	46	Load Multiple words
lwz	rD,d(rA)	32	Load Word and zero
lwzu	rD,d(rA)	33	Load Word and zero with update

---------------
0..5	opcode1
6..10	S
11..15	A
16..31	d
---------------

stb	rS,d(rA)	38	Store Byte
stbu	rS,d(rA)	39	Store Byte with Update
sth	rS,d(rA)	44	Store Halfword
sthu	rS,d(rA)	45	Store Halfword with Update
stmw	rS,d(rA)	47	Store Multiple Words
stw	rS,d(rA)	36	Store Word
stwu	rS,d(rA)	37	Store Word with Update

----------------
0..5	opcode1
6..10	D
11..15	A
16..20	B		NB
21.30	opcode2
31	0
----------------

lbzux	rD,rA,rB	31.119	Load Byte and Zero with Update Indexed
lbzx	rD,rA,rB	31.87	Load Byte and Zero Indexing
lhaux	rD,rA,rB	31.375	Load Halfword Algebraic with Update Indexed
lhax	rD,rA,rB	31.343	Load Halfword Algebraic Indexed
lhbrx	rD,rA,rB	31.790	Load Halfword Byte-Reverse Indexed
lhzux	rD,rA,rB	31.311	Load Halfword and Zero with Update Indexed
lhzx	rD,rA,rB	31.279	Load Halfword and Zero Indexed
lswx	rD,rA,rB	31.533	Load String Word Indexed
lwarx	rD,rA,rB	31.20	Load Word and Reserve Indexed
lwbrx	rD,rA,rB	31.534	Load Word Byte-Reverse Indexed
lwzux	rD,rA,rB	31.55	Load Word and Zero with Update Indexed
lwzx	rD,rA,rB	31.23	Load Word and Zero Indexed

lswi	rD,rA,NB	31.597	Load String Word Immediate

----------------
0..5	opcode1
6..10	S
11..15	A
16..35.3	B		NB
21.30	opcode2
31	0
----------------

stbux	rS,rA,rB	31.247	Store Byte with Update Indexed
stbx	rS,rA,rB	31.215	Store Byte Indexed
sthbrx	rS,rA,rB	31.918	Store Halfword Byte-Reverse Indexed
sthux	rS,rA,rB	31.439	Store Halfword with Update Indexed
sthx	rS,rA,rB	31.407	Store Halfword Indexed
stswx	rS,rA,rB	31.661	Store String Word Indexed
stwbrx	rS,rA,rB	31.662	Store Word Byte-Reverse Indexed
stwcx.	rS,rA,rB	31.150	Store Word Conditional Indexed
stwux	rS,rA,rB	31.183	Store Word with Update Indexed
stwx	rS,rA,rB	31.151	Store Word Indexed

stswi	rS,rA,NB	31.725	Store String Word Immediate

For 64-bit Power PC exist additional operations:

    ld		Load Doubleword
    ldarx		Load Doubleword and Reserve Indexed
    ldu		Load Doubleword with Update
    ldux		Load Doubleword with Update Indexed
    ldx		Load Doubleword Indexed
    lwa		Load Word Algebraic
    lwaux		Load Word Algebraic with update indexed
    lwax		Load Word Algebraic Indexed

    std		Store Doubleword
    stdcx.		Store Doubleword Conditional Indexed
    stdu		Store Doubleword with Update
    stdux		Store Doubleword Indexed with Update
    stdx		Store Doubleword Indexed

68K

Code			Size	Mnemonic		Description
00ss	B,W,L	MOVE	,	 ->
001snnn001<-EA->	W,L	MOVEA	,An		  -> An
0111nnn0<-Data->	B	MOVEQ	#data,Dn	#data -> Dn
0000nnn10s001xxx	W,L	MOVEP	d16(Ax),Dn	d16(Ax) -> Dn
<----Disp------>

0000nnn11s001xxx	W,L	MOVEP	Dn,d16(Ax)	Dn -> d16(Ax)
<----Disp------>

    Note: MOVEM load Block of Register starting with  address,
          RegList is bitmap of registers to load store

010010001s<-EA->	W,L	MOVEM	,	 ->
<---RegList---->

010011001s<-EA->	W,L	MOVEM	,	  ->
<---RegList---->

0100nnn111<-EA->	L	LEA	,An		EA:Addr -> An

0100100001<-EA->	L	PEA			EA:Addr -> -(SP)

1100xxx101000yyy	L	EXG	Dx,Dy		Dx <-> Dy
1100xxx101001yyy	L	EXG	Ax,Ay		Ax <-> Ay
1100xxx110001yyy	L	EXG	Dx,Ay		Dx <-> Ay

Z80

    codes for registers:
    B	0		H	4
    C	1		L	5
    D	2		(HL)	6
    E	3		A	7

Operation		Description			Code
LD	r1,r2		r1 <- r2			40+r1*8+r2

LD	r,n		r  <- n			B	06 nn
                        C	0E nn
                        D	16 nn
                        E	1E nn
                        H	26 nn
                        L	2E nn
                        (HL)	36 nn
                        A	3E nn

LD	r,(ii+n)	r <- (ii + n)		ii 40+r*8+6 nn

LD	(ii+n),r	(ii + n) <- r		IX	DD 70+r nn
                        IY	FD 70+r nn

LD	(ii+n),m	(ii + n) <- m		IX	DD 36 mm nn
                        IY	FD 36 mm nn

LD	A,(BC)		A <- (BC)			0A
LD	A,(DE)		A <- (DE)			1A
LD	A,(nn)		A <- (nn)			3A nn nn
LD	(nn),A		(nn) <- A			32 nn nn
LD	(BC),A		(BC) <- A			02
LD	(DE),A		(DE) <- A			12

LD	rr,nn		rr <- nn		BC	01 nn nn
                        DE	11 nn nn
                        HL	21 nn nn
                        SP	31 nn nn

LD	ii,nn		ii <- nn		IX	DD 21 nn nn
                        IY	FD 21 nn nn

LD	rr,(nn)		rr <- (nn)		BC	ED 4B nn nn
                        DE	ED 5B nn nn
                        HL	2A nn nn
                        SP	ED 7B nn nn

LD	ii,(nn)		ii <- (nn)		IX	DD 2A nn nn
                        IY	FD 2A nn nn

LD	(nn),rr		(nn) <- rr		BC	ED 43 nn nn
                        DE	ED 53 nn nn
                        HL	22 nn nn
                        SP	ED 73 nn nn

LD	(nn),ii		(nn) <- nn		IX	DD 22 nn nn
                        IY	FD 22 nn nn

X86

    (Load Effective Address) =========
LEA	r16,m			8D	/r
LEA	r32,m			8D	/r

    DEST <- ADDRESS (SRC)

    (Move Data) =======================
MOV	r/m8,r8			88 /r
MOV	r/m16,r16		89 /r
MOV	r/m32,r32		89 /r
MOV	r8,r/m8			8A /r
MOV	r16,r/m16		8B /r
MOV	r32,r/m32		8B /r
MOV	AL,moffs8		A0
MOV	AX,moffs16		A1
MOV	EAX,moffs32		A1
MOV	moffs8,AL		A2
MOV	moffs16,AX		A3
MOV	moffs32,EAX		A3
MOV	r8,i8			B0+ rb
MOV	r16,i16			B8+ rw
MOV	r32,i32			B8+ rw
MOV	r/m8,i8			C6 /0
MOV	r/m16,i16		C7 /0
MOV	r/m32,i32		C7 /0

    DEST <- SRC

    (Exchange) =======================
XCHG	AX,r16			90+rw
XCHG	r16,AX			90+rw
XCHG	EAX,r32			90+rd
XCHG	r32,EAX			90+rd
XCHG	r/m8,r8			86/r
XCHG	r8,r/m8			86/r
XCHG	r16,r/m16		87/r
XCHG	r/m16,r16		87/r
XCHG	r/m32,r32		87/r
XCHG	r32,r/m32		87/r

    DEST <-> SRC

IA64

Format M1
-----------
40..37	4
36	m
35..30	X6
29..28	hint
27	x		Opcode = 4.m.x.x6
26..20	r3
19..13	---
12..6	r1
5..0	qp
-------------

ld1{.ldhint}		r1=[r3]		M1	4.0.0.00
ld2{.ldhint}		r1=[r3]		M1	4.0.0.01
ld4{.ldhint}		r1=[r3]		M1	4.0.0.02
ld8{.ldhint}		r1=[r3]		M1	4.0.0.03

ld1.s{.ldhint}		r1=[r3]		M1	4.0.0.04
ld2.s{.ldhint}		r1=[r3]		M1	4.0.0.05
ld4.s{.ldhint}		r1=[r3]		M1	4.0.0.06
ld8.s{.ldhint}		r1=[r3]		M1	4.0.0.07

ld1.a{.ldhint}		r1=[r3]		M1	4.0.0.08
ld2.a{.ldhint}		r1=[r3]		M1	4.0.0.09
ld4.a{.ldhint}		r1=[r3]		M1	4.0.0.0A
ld8.a{.ldhint}		r1=[r3]		M1	4.0.0.0B

ld1.sa{.ldhint}		r1=[r3]		M1	4.0.0.0C
ld2.sa{.ldhint}		r1=[r3]		M1	4.0.0.0D
ld4.sa{.ldhint}		r1=[r3]		M1	4.0.0.0E
ld8.sa{.ldhint}		r1=[r3]		M1	4.0.0.0F

ld1.bias{.ldhint}	r1=[r3]		M1	4.0.0.10
ld2.bias{.ldhint}	r1=[r3]		M1	4.0.0.11
ld4.bias{.ldhint}	r1=[r3]		M1	4.0.0.12
ld8.bias{.ldhint}	r1=[r3]		M1	4.0.0.13

ld1.acq{.ldhint}	r1=[r3]		M1	4.0.0.14
ld2.acq{.ldhint}	r1=[r3]		M1	4.0.0.15
ld4.acq{.ldhint}	r1=[r3]		M1	4.0.0.16
ld8.acq{.ldhint}	r1=[r3]		M1	4.0.0.17

ld8.fill.{.ldhint}	r1=[r3]		M1	4.0.0.1B

ld1.c.clr{.ldhint}	r1=[r3]		M1	4.0.0.20
ld2.c.clr{.ldhint}	r1=[r3]		M1	4.0.0.21
ld4.c.clr{.ldhint}	r1=[r3]		M1	4.0.0.22
ld8.c.clr{.ldhint}	r1=[r3]		M1	4.0.0.23

ld1.c.nc{.ldhint}	r1=[r3]		M1	4.0.0.24
ld2.c.nc{.ldhint}	r1=[r3]		M1	4.0.0.25
ld4.c.nc{.ldhint}	r1=[r3]		M1	4.0.0.26
ld8.c.nc{.ldhint}	r1=[r3]		M1	4.0.0.27

ld1.c.clr.acq{.ldhint}	r1=[r3]		M1	4.0.0.28
ld2.c.clr.acq{.ldhint}	r1=[r3]		M1	4.0.0.29
ld4.c.clr.acq{.ldhint}	r1=[r3]		M1	4.0.0.2A
ld8.c.clr.acq{.ldhint}	r1=[r3]		M1	4.0.0.2B

Format M2
-----------
40..37	4
36	m
35..30	X6
29..28	hint
27	x	Opcode = 4.m.x.x6
26..20	r3
19..13	r2
12..6	r1
5..0	qp
-------------

ld1{.ldhint}		r1=[r3],r2		M2	4.1.0.00
ld2{.ldhint}		r1=[r3],r2		M2	4.1.0.01
ld4{.ldhint}		r1=[r3],r2		M2	4.1.0.02
ld8{.ldhint}		r1=[r3],r2		M2	4.1.0.03

ld1.s{.ldhint}		r1=[r3],r2		M2	4.1.0.04
ld2.s{.ldhint}		r1=[r3],r2		M2	4.1.0.05
ld4.s{.ldhint}		r1=[r3],r2		M2	4.1.0.06
ld8.s{.ldhint}		r1=[r3],r2		M2	4.1.0.07

ld1.a{.ldhint}		r1=[r3],r2		M2	4.1.0.08
ld2.a{.ldhint}		r1=[r3],r2		M2	4.1.0.09
ld4.a{.ldhint}		r1=[r3],r2		M2	4.1.0.0A
ld8.a{.ldhint}		r1=[r3],r2		M2	4.1.0.0B

ld1.sa{.ldhint}		r1=[r3],r2		M2	4.1.0.0C
ld2.sa{.ldhint}		r1=[r3],r2		M2	4.1.0.0D
ld4.sa{.ldhint}		r1=[r3],r2		M2	4.1.0.0E
ld8.sa{.ldhint}		r1=[r3],r2		M2	4.1.0.0F

ld1.bias{.ldhint}	r1=[r3],r2		M2	4.1.0.10
ld2.bias{.ldhint}	r1=[r3],r2		M2	4.1.0.11
ld4.bias{.ldhint}	r1=[r3],r2		M2	4.1.0.12
ld8.bias{.ldhint}	r1=[r3],r2		M2	4.1.0.13

ld1.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.14
ld2.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.15
ld4.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.16
ld8.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.17

ld8.fill.{.ldhint}	r1=[r3],r2		M2	4.1.0.1B

ld1.c.clr{.ldhint}	r1=[r3],r2		M2	4.1.0.20
ld2.c.clr{.ldhint}	r1=[r3],r2		M2	4.1.0.21
ld4.c.clr{.ldhint}	r1=[r3],r2		M2	4.1.0.22
ld8.c.clr{.ldhint}	r1=[r3],r2		M2	4.1.0.23

ld1.c.nc{.ldhint}	r1=[r3],r2		M2	4.1.0.24
ld2.c.nc{.ldhint}	r1=[r3],r2		M2	4.1.0.25
ld4.c.nc{.ldhint}	r1=[r3],r2		M2	4.1.0.26
ld8.c.nc{.ldhint}	r1=[r3],r2		M2	4.1.0.27

ld1.c.clr.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.28
ld2.c.clr.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.29
ld4.c.clr.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.2A
ld8.c.clr.acq{.ldhint}	r1=[r3],r2		M2	4.1.0.2B

Format  M3
------------
40..37	5
36	s
35..30	X6
29..28	hint
27	i		Opcode = 5.x6
26..20	r3
19..13	imm7n
12..6	r1
5..0	qp
-------------

ld1{.ldhint}		r1=[r2],imm9		M3	5.00
ld2{.ldhint}		r1=[r2],imm9		M3	5.01
ld4{.ldhint}		r1=[r2],imm9		M3	5.02
ld8{.ldhint}		r1=[r2],imm9		M3	5.03

ld1.s{.ldhint}		r1=[r2],imm9		M3	5.04
ld2.s{.ldhint}		r1=[r2],imm9		M3	5.05
ld4.s{.ldhint}		r1=[r2],imm9		M3	5.06
ld8.s{.ldhint}		r1=[r2],imm9		M3	5.07

ld1.a{.ldhint}		r1=[r2],imm9		M3	5.08
ld2.a{.ldhint}		r1=[r2],imm9		M3	5.09
ld4.a{.ldhint}		r1=[r2],imm9		M3	5.0A
ld8.a{.ldhint}		r1=[r2],imm9		M3	5.0B

ld1.sa{.ldhint}		r1=[r2],imm9		M3	5.0C
ld2.sa{.ldhint}		r1=[r2],imm9		M3	5.0D
ld4.sa{.ldhint}		r1=[r2],imm9		M3	5.0E
ld8.sa{.ldhint}		r1=[r2],imm9		M3	5.0F

ld1.bias{.ldhint}	r1=[r2],imm9		M3	5.10
ld2.bias{.ldhint}	r1=[r2],imm9		M3	5.11
ld4.bias{.ldhint}	r1=[r2],imm9		M3	5.12
ld8.bias{.ldhint}	r1=[r2],imm9		M3	5.13

ld1.acq{.ldhint}	r1=[r2],imm9		M3	5.14
ld2.acq{.ldhint}	r1=[r2],imm9		M3	5.15
ld4.acq{.ldhint}	r1=[r2],imm9		M3	5.16
ld8.acq{.ldhint}	r1=[r2],imm9		M3	5.17

ld8.fill{.ldhint}	r1=[r2],imm9		M3	5.1B

ld1.c.clr{.ldhint}	r1=[r2],imm9		M3	5.20
ld2.c.clr{.ldhint}	r1=[r2],imm9		M3	5.21
ld4.c.clr{.ldhint}	r1=[r2],imm9		M3	5.22
ld8.c.clr{.ldhint}	r1=[r2],imm9		M3	5.23

ld1.c.nc{.ldhint}	r1=[r2],imm9		M3	5.24
ld2.c.nc{.ldhint}	r1=[r2],imm9		M3	5.25
ld4.c.nc{.ldhint}	r1=[r2],imm9		M3	5.26
ld8.c.nc{.ldhint}	r1=[r2],imm9		M3	5.27

ld1.c.clr.acq{.ldhint}	r1=[r2],imm9		M3	5.28
ld2.c.clr.acq{.ldhint}	r1=[r2],imm9		M3	5.29
ld4.c.clr.acq{.ldhint}	r1=[r2],imm9		M3	5.2A
ld8.c.clr.acq{.ldhint}	r1=[r2],imm9		M3	5.2B

Format  M4
------------
40..37	4
36	m
35..30	X6
29..28	hint	Opcode: 4.m.x.x6
27	x
26..20	r3
19..13	r2
12..6	--
5..0	qp
--------------

st1{.sthint}			[r3]=r2		M4	4.0.0.30
st2{.sthint}			[r3]=r2		M4	4.0.0.31
st4{.sthint}			[r3]=r2		M4	4.0.0.32
st8{.sthint}			[r3]=r2		M4	4.0.0.33

st1.rel{.sthint}		[r3]=r2		M4	4.0.0.34
st2.rel{.sthint}		[r3]=r2		M4	4.0.0.35
st4.rel{.sthint}		[r3]=r2		M4	4.0.0.36
st8.rel{.sthint}		[r3]=r2		M4	4.0.0.37

st8.spill{.sthint}		[r3]=r2		M4	4.0.0.3B

Format  M5
------------
40..37	5
36	s
35..30	X6
29..28	hint	Opcode: 5.x6
27	i
26..20	r3
19..13	r2
12..6	imm7a
5..0	qp
--------------

st1{.sthint}			[r3]=r2,imm9	M5	5.30
st2{.sthint}			[r3]=r2,imm9	M5	5.31
st4{.sthint}			[r3]=r2,imm9	M5	5.32
st8{.sthint}			[r3]=r2,imm9	M5	5.33

st1.rel{.sthint}		[r3]=r2,imm9	M5	5.34
st2.rel{.sthint}		[r3]=r2,imm9	M5	5.35
st4.rel{.sthint}		[r3]=r2,imm9	M5	5.36
st8.rel{.sthint}		[r3]=r2,imm9	M5	5.37

st8.spill{.sthint}		[r3]=r2,imm9	M5	5.3B

Format M16
-----------
40..37	4
36	m
35..30	X6
29..28	hint
27	x		Opcode = 4.m.x.X6
26..20	r3
19..13	r2
12..6	r1
5..0	qp
-----------

xchg1{.ldhint}		r1=[r3],r2		M16	4.0.1.08
xchg2{.ldhint}		r1=[r3],r2		M16	4.0.1.09
xchg4{.ldhint}		r1=[r3],r2		M16	4.0.1.0A
xchg8{.ldhint}		r1=[r3],r2		M16	4.0.1.0B

Format M17
-----------
40..37	4
36	m
35..30	X6
29..28	hint
27	x		Opcode = 4.m.x.X6
26..20	r3
19..16	--
15	s
14..13	I2b
12..6	r1
5..0	qp
-----------

fetchadd4.acq{.ldhint}	r1=[r3],inc3		M17	4.0.1.12
fetchadd8.acq{.ldhint}	r1=[r3],inc3		M17	4.0.1.13
fetchadd4.rel{.ldhint}	r1=[r3],inc3		M17	4.0.1.16
fetchadd8.rel{.ldhint}	r1=[r3],inc3		M17	4.0.1.17

Format	X2
------------
40..37	6
36	i
35..27	imm9d
26..22	imm5c
21	Ic
20	Vc		Opcode = 6.Vc
19..13	ummm7b
12..6	r1
5..0	qp
- - - - - - -
40..0	imm41
--------------
movl			r1 = imm64		X2	6.0

For load smaller constant we can use next sequences:

    or	rd = imm8,  r0
    adds	rd = imm14, r0
    addl	rd = imm22, r0

Because r0 is hard coded to zero.

JVM

== Array Operations

AALOAD						32
AASTORE						53
BALOAD						33
BASTORE						54
CALOAD						34
CASTORE						55
IALOAD						2E
IASTORE						4F
LALOAD						2F
LASTORE						50
SALOAD						35
SASTORE						56

== Simple operations

ALOAD		n				19
ALOAD_0						2A
ALOAD_1						2B
ALOAD_2						2C
ALOAD_3						2D
ASTORE		n				3A
ASTORE_0					4B
ASTORE_1					4C
ASTORE_2					4D
ASTORE_3					4E

ILOAD		n				15
ILOAD_0						1A
ILOAD_1						1B
ILOAD_2						1C
ILOAD_3						1D
ISTORE		n				36
ISTORE_0					3B
ISTORE_1					3C
ISTORE_2					3D
ISTORE_3					3E

LLOAD		n				16
LLOAD_0						1E
LLOAD_1						1F
LLOAD_2						20
LLOAD_3						21
LSTORE		n				37
LSTORE_0					3F
LSTORE_1					40
LSTORE_2					41
LSTORE_3					42

MCS51

MOV	A,Rn		1110 1rrr			Move
MOV	A,direct	1110 0101
MOV	A,@Ri		1110 011i
MOV	A,#data		0111 0100
MOV	Rn,A		1111 1rrr
MOV	Rn,direct	1010 1rrr
MOV	Rn,#data	0111 1rrr
MOV	direct,A	1111 0101
MOV	direct,Rn	1000 1rrr
MOV	directd,directs	1000 0101
MOV	direct,@Ri	1000 011i
MOV	direct,#data	0111 0101
MOV	@Ri,A		1111 011i
MOV	@Ri,direct	1010 011i
MOV	@Ri,#data	0111 011i
MOV	DPTR,data16	1001 0000

MOVC	A,@A+DPTR	1001 0011
MOVC	A,@A+PC		1000 0011

MOVX	A,@Ri		1110 001i			Move External
MOVX	A,@DPTR		1110 0000			Memory
MOVX	@Ri,A		1111 001i
MOVX	@DPTR,A		1111 0000

XCH	A,Rn		1100 1rrr			Exchange
XCH	A,direct	1100 0101
XCH	A,@Ri		1100 011i


35.3.5 INTEGER CONVERTIONS INSTRUCTIONS

    Here discribed next operations:

    o Type Conversions and Related Topics

SPARC

None	(Do it via Memory Load/Store).

ALPHA

Alpha Operate Format
+-------------------------+------------------------+
| 31..26	Opcode	  | 31..26	Opcode	   |
| 25..21	Ra	  | 25..21	Ra	   |
| 20..16	Rb	  | 20..13	LIT        |
| 15..13	SBZ	  | 12		1          |
| 12		0	  | 11..5	Function   |
| 11..5		Function  | 4..0	Rc         |
| 4..0		Rc        |                        |
+-------------------------+------------------------+

Extract Byte
    EXTxx	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    EXTxx	Ra.rq,#b.ib,Rc.wq	!Operate Format

EXTBL		Extract Byte Low
EXTWL		Extract Word Low
EXTLL		Extract Longword Low
EXTQL		Extract Quadword Low
EXTWH		Extract Word High
EXTLH		Extract Longword High
EXTQH		Extract Quadword High

    case
        extbl: 	byte_mask <- 0000 0001 b
        extwX:  byte_mask <- 0000 0011 b
        extlX:  byte_mask <- 0000 1111 b
        extqX:  byte_mask <- 1111 1111 b
    endcase
    case
        extXl:
            byte_loc <- Rbv<2:0> * 8
            temp <- RIGHT_SHIFT(Rav,byte_loc<5:0>)
            Rc <- BYTE_ZAP(temp,NOT(byte_mask))
        extXh:
            byte_loc <- 64 - Rbv<2:0> * 8
            temp <- LEFT_SHIFT(Rav,byte_loc<5:0>)
            Rc <- BYTE_ZAP(temp,NOT(byte_mask))
    endcase

    EXTBL	12.06
    EXTWL	12.16
    EXTLL	12.26
    EXTQL	12.36
    EXTWH	12.5A
    EXTLH	12.6A
    EXTQH	12.7A

    // ----------------------------------------------------------

Byte Insert
    INSxx	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    INSxx	Ra.rq,#b.ib,Rc.wq	!Operate Format

INSBL		Insert Byte Low
INSWL		Insert Word Low
INSLL		Insert Longword Low
INSQL		Insert Quadword Low
INSWH		Insert Word High
INSLH		Insert Longword High
INSQH		Insert Quadword High

    case
        insbl: 	byte_mask <- 0000 0000 0000 0001 b
        inswX:  byte_mask <- 0000 0000 0000 0011 b
        inslX:  byte_mask <- 0000 0000 0000 1111 b
        insqX:  byte_mask <- 0000 0000 1111 1111 b
    endcase
    case
        insXl:
            byte_loc <- Rbv<2:0> * 8
            temp <- LEFT_SHIFT(Rav,byte_loc<5:0>)
            Rc <- BYTE_ZAP(temp,NOT(byte_mask<7:0>))
        insXh:
            byte_loc <- 64 - Rbv<2:0> * 8
            temp <- RIGHT_SHIFT(Rav,byte_loc<5:0>)
            Rc <- BYTE_ZAP(temp,NOT(byte_mask<15:8>))
    endcase

    INSBL	12.0B
    INSWL	12.1B
    INSLL	12.2B
    INSQL	12.3B
    INSWH	12.57
    INSLH	12.67
    INSQH	12.77

    // ----------------------------------------------------------

Zero Bytes
    ZAPx	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    ZAPx	Ra.rq,#b.ib,Rc.wq	!Operate Format

ZAP		Zero Bytes
ZAPNOT		Zero Bytes Not

    case
        ZAP:
            Rc <- BYTE_ZAP(Rav,Rbv<7:0>)
        ZAPNOT:
            Rc <- BYTE_ZAP(Rav,NOT Rbv<7:0>)
    endscase

    ZAP	12.30
    ZAPNOT	12.31

    // ----------------------------------------------------------

Byte  Mask
    MSKx	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    MSKx	Ra.rq,#b.ib,Rc.wq	!Operate Format

MSKBL		Mask Byte Low
MSKWL		Mask Word Low
MSKLL		Mask Longword Low
MSKQL		Mask Quadword Low
MSKWH		Mask Word High
MSKLH		Mask Longword High
MSKQH		Mask Quadword High

    case
        mskbl: 	byte_mask <- 0000 0000 0000 0001 b
        mskwX:  byte_mask <- 0000 0000 0000 0011 b
        msklX:  byte_mask <- 0000 0000 0000 1111 b
        mskqX:  byte_mask <- 0000 0000 1111 1111 b
    endcase
    case
        mskXl:
            Rc <- BYTE_ZAP(Rav,byte_mask<7:0>)
        mskXh:
            Rc <- BYTE_ZAP(Rav,byte_mask<15:8>)
    endcase

    MSKBL	12.02
    MSKWL	12.12
    MSKLL	12.22
    MSKQL	12.32
    MSKWH	12.51
    MSKLH	12.62
    MSKQH	12.72

    // ----------------------------------------------------------

Sign Extend

    SEXTx	Rb.rq,Rc.wq	!Operate Format
    SEXTx	#b.ib,Rc.wq	!Operate Format

    case
        SEXTB:	Rc <- SEXT(Rbv<7:0>)
        SEXTW:	Rc <- SEXT(Rbv<15:0>)
    endcase

    SEXTB	1C.00
    SEXTW	1C.01

    (Ra must be R31)

HP-PA

None Convertions. Only via Load/Store.

MIPS

None convertions. (Use load/store operations).

PowerPC

0..5	opcode1
6..10	S
11..15	A
16..20	0s
21.30	opcode2
31	Rc

            Rc	opcode
extsb	rA,rS		0	31.954	Extend Sign Byte
extsb.	rA,rS		1

    S <- rS[24]
    rA[24-31] <- rS[24-31]
    rA[0-23]  <- (24)S

extsh	rA,rS		0	31.922	Extend Sign Half Word
extsh.	rA,rS		1

    S <- rS[16]
    rA[16-31] <- rS[16-31]
    rA[0-15]  <- (16)S

For 64-bit Power PC
    extsw			Extend Signed Word

68K

Code			Size	Mnemonic		Description
010010001s000nnn	B,W	EXT	Dn		Dn <- sign_ext(
                              part_of_Dn)

Z80

None Such insturctions, need software code

    Example:
    ;  A -> HL
    or	A
    ld	h,0
    jr	p,?1
    dec	h
?1:	ld	l,a

X86

    (Move with Sign Extend) ===========
MOVSX	r16,r/m8		0F BE /r
MOVSX	r32,r/m8		0F BE /r
MOVSX	r32,r/m16		0F BF /r

    DEST <- sign_extend(SRC)

    (Move with Zero Extend) ===========
MOVZX	r16,r/m8		0F BE /r
MOVZX	r32,r/m8		0F BE /r
MOVZX	r32,r/m16		0F BF /r

    DEST <- zero_extend(SRC)

Note:
    Also exist old commands which is used for compatibility
or for preparing for divide...

    (Convert Byte into word) =====
CBW				98
    AX <- sign_extend(AL)

    (Convert Word into Doubleword extended) ==
CWDE				98
    EAX <- sign_extend(AX)

    (Conert Word into Doubleword) =====
CWD				99
    DX:AX <- sign_extend(AX)

    (Convert Doubleword into Quadword)====
CDQ				99
    EDX:EAX <- sign_extend(EAX)

IA64

Format I29
-----------
40..37	0
36	--
35..33	x3
32..27	x6
26..20	r3	Opcode = 0.x3.x6
19..13	--
12..6	r1
5..0	qp
-------------

zxt1	r1=r3		I29	0.0.10			Zero Extend
zxt2	r1=r3		I29	0.0.11
zxt4	r1=r3		I29	0.0.12

sxt1	r1=r3		I29	0.0.14			Sign Extend
sxt2	r1=r3		I29	0.0.15
sxt4	r1=r3		I29	0.0.16

JVM

I2L		Integer => Long			85
L2I		Long    => Integer		88

I2B		Integer => Byte			91
I2C		Integer => Char			92
I2S		Intger  => Short		93

Note:
    Convertions from smaller types performed using Array Load/Store
operations.

MCS51

    No such operations on simple 8-bit microcontroller.
Possibly to write complex code to do it.


35.3.6. COMPARES AND CONDITIONAL JUMPS INSTRUCTIONS

SPARC

SPARC format 2
+-----------------------+
| 31..30	00	|
| 29		a	|
| 28	 	0	|
| 27..25	rcond	|
| 24..22	opcode	|
| 21..20	disp16hi|
| 19		p	|
| 18..14	rs1	|
| 12..0		disp16lo|
+-----------------------+

(Branch on Integer Register with Prediction)

Operation	opcode	rcond	Description
brz		011	001	Branch on Register zero
brlez		011	010	Branch on Register Less Than or Equal to Zero
brlz		011	011	Branch on Register Less Then Zero
brnz		011	101	Branch on Register not zero
brgz		011	110	Branch on Register Greater that zero
brgez		011	111	Branch in Register Greater Than or Equal to 0

ops{,a}{,pt|,pn}	reg(rs1),label

Options:					p
    ,pt	Predict Taken	(default)
    ,pn	Predict Not Taken

    ,a	Annul

    Branch		Test
    brnz		not Z
    brz		Z
    brgez		not N
    brlz		N
    brlez		N or Z
    brgz		not (N or Z)

    if (cond)
    {
        PC <- PC + ( 4 * sign_extend(disp16) )
    }

SPARC format 2
+-----------------------+
| 31..30	00	|
| 29		a	|
| 28..25	cond	|
| 24..22	opcode	|
| 21..0		disp22	|
+-----------------------+

(Branch on Integer Conditional Codes)

Operation	opcode	rcond	Description
ba		010	1000	Bracnch Always
bn		010	0000	Branch Never
bne		010	1001	Branch on Not Equal
be		010	0001	Branch on Equal
bg		010	1010	Branch on Greater
ble		010	0010	Branch on Less or Equal
bge		010	1011	Branch on Greater or Equal
bl		010	0011	Branch on Less
bgu		010	1100	Branch on Greater Unsigned
bleu		010	0100	Branch on Less or Equal Unsigned
bcc		010	1101	Branch on Carry Clear (Greater than or Equal US)
bcs		010	0101	Branch on Carry Set (Less than, Unsigned)
bpos		010	1110	Branch on Positive
bneg		010	0110	Branch on Negative
bvc		010	1111	Branch on Overflow Clear
bvs		010	0111	Branch on Overflow Set

ops {,a}	label

    Operation	Synonim
    bne		bnz
    be		bz
    bcc		bgeu
    bcs		blu

    if (cond)
    {
        PC <- PC + ( 4 * sign_extend(disp22) )
    }

SPARC format 2
+-----------------------+
| 31..30	00	|
| 29		a	|
| 28..25	cond	|
| 24..22	opcode	|
| 21		cc1	|
| 20		cc0	|
| 19		p	|
| 18..0		disp19	|
+-----------------------+

(Branch on Integer Conditional Codes with Prediction)

Operation	opcode	rcond	Description
bpa		001	1000	Bracnch Always
bpn		001	0000	Branch Never
bpne		001	1001	Branch on Not Equal
bpe		001	0001	Branch on Equal
bpg		001	1010	Branch on Greater
bple		001	0010	Branch on Less or Equal
bpge		001	1011	Branch on Greater or Equal
bpl		001	0011	Branch on Less
bpgu		001	1100	Branch on Greater Unsigned
bpleu		001	0100	Branch on Less or Equal Unsigned
bpcc		001	1101	Branch on Carry Clear (Greater than or Equal US)
bpcs		001	0101	Branch on Carry Set (Less than, Unsigned)
bppos		001	1110	Branch on Positive
bpneg		001	0110	Branch on Negative
bpvc		001	1111	Branch on Overflow Clear
bpvs		001	0111	Branch on Overflow Set

ops {,a} {,pt | ,pn }	i_or_x_cc, label

    cc1    cc0	Conditional code
    0  	0	icc
    0	1	---
    1	0	xcc
    1	1	---

    if (cond)
    {
        PC <- PC + ( 4 * sign_extend(disp19) )
    }

ALPHA

Alpha Branch Format
+-----------------------+
| 31..26	Opcode	|
| 25..21	Ra	|
| 20..0		disp	|
+-----------------------+

Conditional Branch
    Bxx	Ra.rq,disp.al		!Branch format

    { update PC }
    va <- PC + (4 * SEXT(disp))
    if (TEST(Rav,condition) THEN PC <- va

    BEQ	Branch if register Equal to Zero
    BGE	Branch if Register Greater Than or Equal to Zero
    BGT	Branch if Register Greater than zero
    BLBC	Branch if Register Low Bit is clear
    BLBS	Branch if Register Low bit is Set
    BLE	Branch if Register Less than or Equal to Zero
    BLT	Branch if Register Less that zero
    BNE	Branch if Register Not equal to zero

    BEQ	39
    BGE	3E
    BGT	3F
    BLBC	38
    BLBS	3C
    BLE	3B
    BLT	3A
    BNE	3D

Alpha Operate Format
+-------------------------+------------------------+
| 31..26	Opcode	  | 31..26	Opcode	   |
| 25..21	Ra	  | 25..21	Ra	   |
| 20..16	Rb	  | 20..13	LIT        |
| 15..13	SBZ	  | 12		1          |
| 12		0	  | 11..5	Function   |
| 11..5		Function  | 4..0	Rc         |
| 4..0		Rc        |                        |
+-------------------------+------------------------+

Integer Signed Compare
    CMPxx	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    CMPxx	Ra,rq,#b.ib,Rc.wq	!Operate Format

    If Rav SIGNED_RELATION Rbv then
        Rc <- 1
    ELSE
        Rc <- 0

    CMPEQ	Compare Signed Quadword Equal
    CMPLE	Compare Signed Quadword Less Than or Equal
    CMPLT	Compare Signed Quadword Less Than

    CMPEQ	10.2D
    CMPLE	10.6D
    CMPLT	10.4D

Integer Unsigned Compare
    CMPUxx	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    CMPUxx	Ra,rq,#b.ib,Rc.wq	!Operate Format

    If Rav UNSIGNED_RELATION Rbv then
        Rc <- 1
    ELSE
        Rc <- 0

    CMPULE	Compare Signed Quadword Less Than or Equal
    CMPULT	Compare Signed Quadword Less Than

    CMPULE	10.3D
    CMPULT	10.1D

HP-PA

+---------------------------+-------------------+-----------------------+
|	Len	Value       |			|			|
|	6	xx          |			|			|
|	5	r2          |	5	r	|	5	p	|
|	5	r1          |	5	im5	|			|
|	3	c	    |			|			|
|	11	w1          |			|			|
|	1	n           |			|			|
|	1	w	    |			|			|
+---------------------------+-------------------+-----------------------+

Command

                xx
COMBT,cond,n	r1,r2,target	20	Compare and Branch if True
COMBF,cond,n	r1,r2,target	22	Compare and Branch if False
COMIBT,cond,n	i,r,target	21	Compare Immediate and Branch if True
COMIBF,cond,n	i,r,target	23	Compare Immediate and Branch if False

    Compare: GR[r1] + ~GR[r2] + 1			// COMBT/COMBF
    Compare: sign_ext(im5) + ~GR[r] + 1		// COMIBT/COMIBF

    disp <- lshift(sign_ext({w1,w},2))
    if (cond_satisfied)				// if true
    if (!cond_satisfied)				// if false
        IAQQ_Next <- IAQQ_Front + disp + 8
    if (n)
        if (disp < 0)
            PSW[N] <- !cond_satisfied
        else
            PSW[N] <- cond_satisfied

Additional operations:
ADDBT,cond,n	r1,r2,target	28	Add and Branch if true
ADDBF,cond,n	r1,r2,target	2A	Add and Branch if false
ADDIBT,cond,n	i,r,target	29	Add Immediate and Branch if true
ADDIBF,cond,n	i,r,target	2B	Add Immediate and Branch if false

Note:	The same as compare but calculated instead of compare
        GR[r2] <- GR[r1] + GR[r2]
    or	GR[r]  <- sign_ext(im5) + GR[r]

BVB,cond,n	r,target	30	Branch on Variable bit

Note:	Based on test lshift(GR[r],CR[11])

BB,cond,n	r,p,target	31	Branch on bit (fixed)

MIPS

+-------------------------------+
|	Len	Value		|
|	6	opcode		|
|	5	rs		|
|	5	rt		|
|	16	offset		|
+-------------------------------+

Command			Opcode		Description
BEQ	rs,rt,offset	0001 00		Branch on Equal		     (MIPS I)
BEQL	rs,rt,offset	0101 00		Branch on Equal Likely	     (MIPS II)
BNE	rs,rt,offset	0001 01		Branch on Not Equal	     (MIPS I)
BNEL	rs,rt,offset	0101 01		Branch on Not Equal Likely   (MIPS II)

    cond <- (GRP[rs] COMPARE GPR[rt])
    if (cond)
    {
        PC <- PC + sign_ext(offset * 4)
    }
    if (Branch likely)
    {
        NullifyCurrentInstruction()
    }

+-------------------------------+
|	Len	Value		|
|	6	000001 = REGIMM |
|	5	rs		|
|	5	xxxx		|
|	16	offset		|
+-------------------------------+

                (Likely is MIPS II, other MIPS I)
Command			xxxx	Desrcription
BGEZ	rs,offset	00001	Branch on Greater than or Equal to zero
BGEZAL	rs,offset	10001	Branch on Greater than or Equal to zero
                and link
BGEZALL	rs,offset	10011	Branch on Greater than or Equal to zero
                and link likely
BGEZL	rs,offset	00011	Branch on Greater than or Equal to zero
                Likely

BLTZ	rs,offset	00000	Branch on less than zero
BLTZAL	rs,offset	10000	Branch on less than zero and link
BLTZALL	rs,offset	10010	Branch on less than zero and link likely
BLTZL	rs,offset	00010	Branch on less than zero Likely

    cond	<-  GPR[rs] COMPARE  0
    GPR[31] <- PC + 8			// Link only
    if (cond)
        PC <- 	PC + sign_ext(offset * 4)
    else					// Likely only
        NullifyCurrentInstruction	// Likely only

+-------------------------------+
|	Len	Value		|
|	6	opcode	        |
|	5	rs		|
|	5	0		|
|	16	offset		|
+-------------------------------+

                (Likely is MIPS II, other MIPS I)
Command			opcode
BGTZ	rs,offset	000111	Branch on Greater than zero
BGTZL	rs,offset	010111	Branch on Greater than zero Likely
BLEZ	rs,offset	000110	Branch on Less than equal to zero
BLEZL	rs,offset	010110	Branch on Less than equal to zero likely

    cond <- GPT[rs] COMPARE 0
    if (cond)
    {
        PC <- PC + sign_ext(offset * 4)
    } else {
        NullifyCurrentInstuction		// Likely only
    }

PowerPC

0..5	opcode1
6..10	BO
11..15	NI
16..29	BD
30	AA
31	LK

            AA	LK	opcode
bc	BI,BO,target	0	0	16		Branch conditional
bca	BI,BO,target	1	0
bcl	BI,BO,target	0	1
bcla	BI,BO,target	1	1

    if (NOT BO[2])  { CTR <- CTR - 1}
    ctr_ok  = BO[2] OR ((CTR != 0) XOR BO[3])
    cond_ok = BO[0] OR ((NOT (CR[BI])) EQV (NOT BO[1]))	// !!!
    condition_ok = ctr_ok AND cond_ok

    if condition_ok
    {
        if AA { NIA  <- sign_ext(BD * 4);	}
        else  { NIA  <- CIA + sing_ext(BD * 4); }
        if LK { LR   <- CIA + 4			}
    }

Simplifyed Mnemonics:
blt	target			bc	12,0,target
bne	cr2,target		bc	4,10,target
bdnz	target			bc	16,0,target

    // ----------------------------------------------------------

0..5	opcode1
6..10	BO
11..15	BI
16..20	0
21..30	opcode2
31	LK

            LK	opcode
bcctr	BO,BI		0	19.528		Branch Condiional to Count
bcctrl	BO,BI		1			Register

    cond_ok <- BO[0] OR (CR[BI] EQV BO[1])			// !!!
    if (cond_ok)
        NIA <- CTR
    if (LK)
        LR  <- CIA + 4

Simplyfied Mnemonics:
bltctr			bcctr	12,0
bnectr	cr2		bcctr	4,10

bclr	BO,BI		0	19.16		Branch Conditional to
bclrl	BO,BI		1			Link Register

    if (NOT BO[2])  { CTR <- CTR - 1}
    ctr_ok  = BO[2] OR ((CTR != 0) XOR BO[3])
    cond_ok = BO[0] OR ((NOT (CR[BI])) EQV (NOT BO[1]))	// !!!
    condition_ok = ctr_ok AND cond_ok

    if condition_ok
        NIA <- LR * 4
    if LK
        LR  <- CIA + 4

Simplyfied Mnemonics:
bltlr			bclr	12,0
bnelr	cr2		bclr	4,10
bdnzrl			bclr	16,0

    // ----------------------------------------------------------

0..5	opcode1			0..5  opcode1
6..8	crfD			6..9	crfD
9	0			9	0
10	L			10	L
11..15	A			11..15	A
16..20	B			16..31	SIMM or UIMM
21..30	opcode2
31	0

cmp	crfD,L,rA,rB		31.0		Compare
cmpi	crfD,L,rA,SIMM		11		Compare Immediate
cmpl	crfD,L,rA,rB		31.32		Compare Logical
cmpli	crfD,L,rA,UIMM		10		Compare Logical Immediate

    L = 0 32-bit operation
    L = 1 64-bit operation

    if Logical then all compares are Unsigned...
    Else				 Signed...

    a <- rA;
    b <- rB;		// Not Immediate
    b <- sign_ext(SIMM)	// Immediate Signed
    b <- UIMM		// Immediate Unsigned

    if (a < b) then c <- 100b
    else if (a > b) then c <- 010b
    else c <- 001
    CR[4 * crfD] <-   { c, XER[SO] }

    // ----------------------------------------------------------

Note:
    Operations below is usefull for calculate superposition of
conditions.

0..5	opcode1
6..10	crbD
11..15	crbA
16..20	crbB
21..30	opcode2
31	0

             opcode
crand	crbD,crbA,crbB	   19.257	Conditional Register AND
crandc	crbD,crbA,crbB	   19.129	Conditional Register AND-NOT
creqv	crbD,crbA,crbB	   19.289	Conditional Register Equivalent
crnand	crbD,crbA,crbB	   19.225	Conditional Register NAND
crnor	crbD,crbA,crbB	   19.33	Conditional Register NOR
cror	crbD,crbA,crbB	   19.449	Conditional Register OR
crorc	crbD,crbA,crbB	   19.417	Conditional Register OR-NOT
crxor	crbD,crbA,crbB	   19.193	Conditional Register XOR

0..5	opcode1
6..8	crfD
9..20	0s
21..30	opcode2
31	0

mcrxr	crfD		19.512		Move to Conditional Register from XER

    CR[4*crfD+3] <- XER[0..3]
    XER[0..3]    <- 0

Use this instruction for move from XER into conditional registers.

0..5	opcode1
6..10	D
11..20	0s
21..30	opcode2
31	0

mfcr	rD		31.19		Move from Conditional Register

    rD <- CR

0..5	opcode1
6..10	S
11	0
12..19	CRM
20	0
21..30	opcode2
31	0

mtcrf	CRM,rS		31.144		Move to Conditional Register Fields

        mask <- {100h CRM[0]}.... {100h CRM[7]}
        CR   <-  (rS[32-63] & mask) | (CR & ~ mask)

68K

Code			Size	Mnemonic		Description
1011nnn0ss<-EA->	B,W,L	CMP	,Dn		setf(Dn - )
1011nnns11<-EA->	W,L	CMPA	,An		setf(An - )
00001100ss<-EA->	B,W,L	CMPI	#Im,	setf(-#Im)
1011yyy1ss001xxx	B,W,L	CMPM	(Ay)+,(Ax)+

0110cccc<-Disp->	B,W	Bcc	ds		if (cond)
                              PC <- PC + Disp

0101cccc11001nnn	W	DBcc	Dn,ds		if (!cond)
<--Displayment->					  Dn - 1 -> Dn
                            if (Dn != -1)
                              PC + Disp -> PC

    cond	cccc	Description
    F	0000	False			1		(not for Bcc)
    T	0001	True			0		(not for Bcc)
    HI	0010	High			C + N = 0
    LS	0011	Low or Same		C + N = 1
    CC	0100	Carry Clear		C = 0
    CS	0101	Carry Set		C = 1
    NE	0110	Not Equal		Z = 0
    EQ	0111	Equal			Z = 1
    VC	1000	Overflow Clear		V = 0
    VS	1001	Overflow Set		V = 1
    PL	1010	Plus			N = 0
    MI	1011	Minus			N = 1
    GE	1100	Greater Equal		N XOR V = 0
    LT	1101	Less than		N XOR V = 1
    GT	1110	greater than		Z + (N XOR V) = 0
    LE	1111	Less or Equal		Z + (N XOR V) = 1

01001010ss<-EA->	B,W,L	TST			setf( - 0)
0100101011<-EA->	B	TAS			setf( - 0)
                            bit 7, <- 1

Z80

Operation		Description			Code
CALL	cc,nn		if (cc)				cc	code
                PUSH	PC		NZ	C4 nn nn
                PC <- nn		Z	CC nn nn
                            NC	D4 nn nn
                            C	DC nn nn
                            PO	E4 nn nn
                            PE	EC nn nn
                            P	F4 nn nn
                            M	FC nn nn

JP	cc,nn		if (cc)				cc	code
                PC <- nn		NZ	C2 nn nn
                            Z	CA nn nn
                            NC	D2 nn nn
                            C	DA nn nn
                            PO	E2 nn nn
                            PE	EA nn nn
                            P	F2 nn nn
                            M	FA nn nn

JR	cond,end	if (cond)			cond	code
                PC <- PC + sext(e)	NZ	20 ee
                            Z	28 ee
                            NC	30 ee
                            C	38 ee

CP	r		setf(A - r)			B8+r
CP	n		setf(A - n)			FE nn
CP	(ii+n)						ii CB nn BE

DJNZ	e		B <- B - 1			10 ee
            if (B != 0)
                PC <- PC + sext(e)

RET	cc		if (cc)				cc	code
                POP	PC		NZ	C0
                            Z	C8
                            NC	D0
                            C	D8
                            PO	E0
                            PE	E8
                            P	F0
                            M	F8

        cc	Description
        C	carry
        NC	not carry
        Z	zero
        NZ	not zero
        M	minus
        P	plus
        PE	parity even
        PO	parity odd

X86

    (Compare ) =================
CMP	AL,imm8			3C 	ib
CMP	AX,imm16		3D 	iw
CMP	EAX,imm32		3D	id
CMP	r/m8,imm8		80/7	ib
CMP	r/m16,imm16		81/7	iw
CMP	r/m32,imm32		81/7	id
CMP	r/m16,imm8		83/7	iw
CMP	r/m32,imm8		83/7	iw
CMP	r/m8,r8			38/r
CMP	r/m16,r16		39/r
CMP	r/m32,r32		39/r
CMP	r8,r/m8			3A/r
CMP	r16,r/m16		3B/r
CMP	r32,r/m32		3B/r

    Set_Flags(DEST - SRC)

    (Logical Compare ) =================
TEST	AL,imm8			A8 ib
TEST	AX,iim16		A9 iw
TEST	EAX,imm32		A9 id
TEST	r/m8,imm8		F6 /0 ib
TEST	r/m16,imm16		F7 /0 iw
TEST	r/m32,imm32		F7 /0 id
TEST	r/m8,r8			84 /r
TEST	r/m16,r16		85 /r
TEST	r/m32,r32		85 /r

    (Condition Jump) ====================
JA	rel8			77 cb
JAE	rel8			73 cb
JB	rel8			72 cb
JBE	rel8			76 cb
JC	rel8			72 cb
JE	rel8			74 cb
JG	rel8			7F cb
JGE	rel8			7D cb
JL	rel8			7C cb
JLE	rel8			7E cb
JNA	rel8			76 cb
JNAE	rel8			72 cb
JNB	rel8			73 cb
JNBE	rel8			77 cb
JNC	rel8			73 cb
JNE	rel8			75 cb
JNG	rel8			7E cb
JNGE	rel8			7C cb
JNL	rel8			7D cb
JNLE	rel8			7F cb
JNO	rel8			71 cb
JNP	rel8			7B cb
JNS	rel8			79 cb
JNZ	rel8			75 cb
JO	rel8			70 cb
JP	rel8			7A cb
JPE	rel8			7A cb
JPO	rel8			7B cb
JS	rel8			78 cb
JZ	rel8			74 cb
JA	rel16/32		0F 87 cw/cd
JAE	rel16/32		0F 83 cw/cd
JB	rel16/32		0F 82 cw/cd
JBE	rel16/32		0F 86 cw/cd
JC	rel16/32		0F 82 cw/cd
JE	rel16/32		0F 84 cw/cd
JG	rel16/32		0F 8F cw/cd
JGE	rel16/32		0F 8D cw/cd
JL	rel16/32		0F 8C cw/cd
JLE	rel16/32		0F 8E cw/cd
JNA	rel16/32		0F 86 cw/cd
JNAE	rel16/32		0F 82 cw/cd
JNB	rel16/32		0F 83 cw/cd
JNBE	rel16/32		0F 87 cw/cd
JNC	rel16/32		0F 83 cw/cd
JNE	rel16/32		0F 85 cw/cd
JNG	rel16/32		0F 8E cw/cd
JNGE	rel16/32		0F 8C cw/cd
JNL	rel16/32		0F 8D cw/cd
JNLE	rel16/32		0F 8F cw/cd
JNO	rel16/32		0F 81 cw/cd
JNP	rel16/32		0F 8B cw/cd
JNS	rel16/32		0F 89 cw/cd
JNZ	rel16/32		0F 85 cw/cd
JO	rel16/32		0F 80 cw/cd
JP	rel16/32		0F 8A cw/cd
JPE	rel16/32		0F 8A cw/cd
JPO	rel16/32		0F 8B cw/cd
JS	rel16/32		0F 88 cw/cd
JZ	rel16/32		0F 84 cw/cd

    if (condition)	EIP <- EIP + sign_extend(rel)

cc		condition		description		S	US
A/NBE		(CF = 0) AND (ZF = 0)	Above				>
AE/JNB/JNC	(CF = 0)		Equal				>=
B/NAE/JC	(CF = 1)		Below				<
BE/NA		(CF = 1) OR  (ZF = 1)   Below Equal			<=
E/Z		(ZF = 1)		Equal			==	==
G/NLE		(SF = OF) AND (ZF = 0)  Greater			>
GE/NL		(SF = OF)		Greater Equal		>=
L/NGE		(SF <> OF)		Less			<
LE/NG		(SF <> OF) OR (ZF = 1)	Less Equal		<=
NE/NZ		(ZF = 0)		Not Equal		!=	!=
NO		(OF = 0)		No Overflow		XX
NP/PO		(PF = 0)		Parity Odd
NS		(SF = 0)		No Sign (Positive)	XX
O		(OF = 1)		Overlow			XX
P/PE		(PF = 1)		Parity Even
S		(SF = 1)		Sign (Negative)		XX

    (Jump if CX zero) ====================
JCXZ	rel8			E3	cb
JECXZ	rel8			E3	cb

    if (E)CX == 0)	  EIP <- EIP + sign_extend(rel)

    (Loop Control with CX counter) =======
LOOP		rel8		E2	cb
LOOPE/LOOPZ	rel8		E1	cb
LOOPNE/LOOPNZ	rel8		E0	cb

    TO DO: Insert Description Later

IA64

Format A6
------------
40..37	opcode
36	tb
35..34	X2
33	ta
32..27	p2	Base code = opcode.x2.tb.ta.c
26..20	r3
19..13	r2
12	c
11..6	p1
5..0	qp
--------------

cmp.lt		p1,p2=r2,r3	A6	C.0.0.0.0	Integer compare
cmp.ltu		p1,p2=r2,r3	A6	D.0.0.0.0
cmp.eq		p1,p2=r2,r3	A6	E.0.0.0.0
cmp.lt.unc	p1,p2=r2,r3	A6	C.0.0.0.1
cmp.ltu.unc	p1,p2=r2,r3	A6	D.0.0.0.1
cmp.eq.unc	p1,p2=r2,r3	A6	E.0.0.0.1
cmp.eq.and	p1,p2=r2,r3	A6	C.0.0.1.0
cmp.eq.or	p1,p2=r2,r3	A6	D.0.0.1.0
cmp.eq.or.andcm	p1,p2=r2,r3	A6	E.0.0.1.0
cmp.ne.and	p1,p2=r2,r3	A6	C.0.0.1.1
cmp.ne.or	p1,p2=r2,r3	A6	D.0.0.1.1
cmp.ne.or.andcm	p1,p2=r2,r3	A6	E.0.0.1.1

Format A7
------------
40..37	opcode
36	tb
35..34	X2
33	ta
32..27	p2	Base code = opcode.x2.tb.ta.c
26..20	r3
19..13	0
12	c
11..6	p1
5..0	qp
--------------

cmp.gt.and	p1,p2=r0,r3	A7	C.0.1.0.0	Integer Compare to 0
cmp.gt.or	p1,p2=r0,r3	A7	D.0.1.0.0
cmp.or.andcm	p1,p2=r0,r3	A7	E.0.1.0.0
cmp.le.and	p1,p2=r0,r3	A7	C.0.1.0.1
cmp.le.or	p1,p2=r0,r3	A7	D.0.1.0.1
cmp.le.or.andcm	p1,p2=r0,r3	A7	E.0.1.0.1
cmp.ge.and	p1,p2=r0,r3	A7	C.0.1.1.0
cmp.ge.or	p1,p2=r0,r3	A7	D.0.1.1.0
cmp.ge.or.andcm	p1,p2=r0,r3	A7	E.0.1.1.0
cmp.lt.and	p1,p2=r0,r3	A7	C.0.1.1.1
cmp.lt.or	p1,p2=r0,r3	A7	D.0.1.1.1
cmp.lt.andcm	p1,p2=r0,r3	A7	E.0.1.1.1

Note:	r0 is actual GPR # 0.

Format A8
------------
40..37	opcode
36	s
35..34	X2
33	ta
32..27	p2	Base code = opcode.x2.ta.c
26..20	r3
19..13	imm7b
12	c
11..6	p1
5..0	qp
--------------

cmp.lt		p1,p2=imm8,r3	A6	C.2.0.0	Integer immediate compare
cmp.ltu		p1,p2=imm8,r3	A6	D.2.0.0
cmp.eq		p1,p2=imm8,r3	A6	E.2.0.0
cmp.lt.unc	p1,p2=imm8,r3	A6	C.2.0.1
cmp.ltu.unc	p1,p2=imm8,r3	A6	D.2.0.1
cmp.eq.unc	p1,p2=imm8,r3	A6	E.2.0.1
cmp.eq.and	p1,p2=imm8,r3	A6	C.2.1.0
cmp.eq.or	p1,p2=imm8,r3	A6	D.2.1.0
cmp.eq.or.andcm	p1,p2=imm8,r3	A6	E.2.1.0
cmp.ne.and	p1,p2=imm8,r3	A6	C.2.1.1
cmp.ne.or	p1,p2=imm8,r3	A6	D.2.1.1
cmp.ne.or.andcm	p1,p2=imm8,r3	A6	E.2.1.1

Format	B1 or B2
--------------
40..37	4
36	s
35	d
34..33	dh
32..13	imm20b		Opcode = 4.btype
12	p
11..9	---
8..6	btype
5..0	qp
---------------

br.cond{.bwh.ph.dh}  tgt25	B1	4.0	IP-Relative Branch
br.wexit{.bwh.ph.dh} tgt25	B1	4.2
br.wtop{.bwh.ph.dh}  tgt25	B1	4.3
br.cloop{.bwh.ph.dh} tgt25	B2	4.5
br.cexit{.bwh.ph.dh} tgt25	B2	4.6
br.ctop{.bwh.ph.dh}  tgt25	B2	4.7

Format B4
--------------
40..37	0
36	--
35	d
34..33	wh
32..27	x6
26..16	--	Opcode = 0.x6.btype
15..13	b2
12	p
11..9	--
8..6	btype
5..0	qp
--------------

br.cond{.bwh.ph.dh}	b1=b2	B5	0.20.0

JVM

LCMP			94	Long compare

                (Address Compare)
IF_ACMPEQ label		A5	a == b
IF_ACMPNE label		A6	a != b
IFNONULL  label		C7	a != null
IFNULL    label		C6	a == null

                (Integer Compare)
IF_ICMPEQ label		9F	a == b
IF_ICMPGE label		A2	a >= b
IF_ICMPGT label		A3	a > b
IF_ICMPLE label		A4	a <= b
IF_ICMPLT label		A1	a < b
IF_ICMPNE label		A0	a != b

                (Integer compare with zero)
IFEQ	  label		99	a == 0
IFGE	  label		9C	a >= 0
IFGT	  label		9D	a >  0
IFLE	  label		9E	a <= 0
IFLT	  label		9B	a <  0
IFNE	  label		9A	a != 0

MCS51

JC	rel		0100 0000 	PC <- PC + 2
                        if (C == 1)
                            PC <- PC + rel

JNC	rel		0101 0000 	PC <- PC + 2
                        if (C == 0)
                            PC <- PC + rel

JZ	rel		0110 0000 	PC <- PC + 2
                        if (Z == 1)
                            PC <- PC + rel

JNZ	rel		0111 0000 	PC <- PC + 2
                        if (Z == 0)
                            PC <- PC + rel

CJNE	A,direct,rel  1011 0101    PC <- PC + 3
                        if (A != direct)
                            PC <- PC + rel

CJNE	A,#data,rel   1011 0100  	PC <- PC + 3
                        if (A != data)
                            PC <- PC + rel

CJNE	Ri,#data,rel  1011 1rrr      PC <- PC + 3
                        if (Ri != data)
                            PC <- PC + rel

CJNE	@Ri,#data,rel 1011 011i  	PC <- PC + 3
                        if ((Ri) != data)
                            PC <- PC + rel

Note: CJNE: if operand1 < operand 2 then C <-1 else C <- 0

DJNZ	Ri,rel	 	1101 1rrr 		PC <- PC + 2
                        Rn <- Rn - 1
                        if (Rn != 0)
                            PC <- PC + rel

DJNZ	direct,rel	1101 0101  	PC <- PC + 2
                        (direct) <- (direct) - 1

Additional:
JB	bit,rel		Jump if Bit set
JNB	bit,rel		Jump if Bit Not set
JBC	bit,rel		Jump and clear bit


35.3.7. UNCONDITIONAL JUMPS AND CALLS INSTRUCTIONS

// ----------------------------------------------------------------------

SPARC

SPARC format 1
+-----------------------+
| 21..30	01	|
| 29..0		disp30	|
+-----------------------+

Operation		Description
call			Call and Link

call	label

    r15 <- PC			(Link Address)
                    [Out Register 7]
    PC  <- PC + (4 * sign_ext(disp30))

SPARC format 3
+-----------------------+-----------------------+
| 31..30	10	| 31..30	10	|
| 29..25	rd	| 29..25	rd	|
| 24..19	op3	| 24..19	op3	|
| 18..14	rs1	| 18..14	rs1	|
| 13		i=0	| 13		i=1	|
| 12..5		--	| 12..0		simm13	|
| 4..0		rs2	|			|
+-----------------------+-----------------------+

Operation	op3		Description
jmpl		11 1000		Jump and Link

jmpl	address,reg(rd)

    rd <-	PC
    if (i = 0)
    {
        PC <- reg(rs1) + reg(rs2)
    } else {
        PC <- reg(rs1) + sign_extend(simm12)
    }

Note:	JUMPL with rd = 0 can be used for return from subroutine.
    (Typical Return address is r[31]+8 if a nonleaf routine
    (i.e. routine, which used SAVE instruction is entered by CALL),
    or r[15]+8 if this is leaf routine, if entered by CALL or JMPL
    with rd = 15.

SPARC format 3
+-----------------------+-----------------------+
| 31..30	10	| 31..30	10	|
| 29..25	---	| 29..25	---	|
| 24..19	op3	| 24..19	op3	|
| 18..14	rs1	| 18..14	rs1	|
| 13		i=0	| 13		i=1	|
| 12..5		--	| 12..0		simm13	|
| 4..0		rs2	|			|
+-----------------------+-----------------------+

Operation	op3		description
return		11 1001		Return

return	address

    if (i = 0)
    {
        PC <- r[rs1] + r[rs2]
    } else {
        PC <- r[rs1] + sign_ext(simm13)
    }

SPARC format 3
+-----------------------+-----------------------+
| 31..30	10	| 31..30	10	|
| 29..25	rd	| 29..25	rd	|
| 24..19	op3	| 24..19	op3	|
| 18..14	rs1	| 18..14	rs1	|
| 13		i=0	| 13		i=1	|
| 12..5		--	| 12..0		simm13	|
| 4..0		rs2	|			|
+-----------------------+-----------------------+

Operation	op3		Description
save		11 1100		Save caller's registers window
restore		11 1101		Restore caller's registers window

save	reg(rs1),reg(rs2),reg(rd)
restore reg(rs1),simm13,reg(rd)

Note:
    Save instruction:
        "out" registers  become "in" registers
        "out" and "local" become zero or value from executing process

    restor instruction:
        "in" register become "out" registers

    TO DO: Insert Here Description of Register Windows on SPARC

SPARC Format 3
+-----------------------+
| 31..30	10	|
| 29..25	fcn	|
| 24..19	op3	|
| 18..0		--	|
+-----------------------+

Operation	op3		fcn	Description
saved		11 0001		0	Window has been saved
restored	11 0001		1	Window has been restored

saved			<< No operand(s) >>
restored		<< No operand(s) >>

Modify saved/restored counters

ALPHA

Alpha Branch Format
+-----------------------+
| 31..26	Opcode	|
| 25..21	Ra	|
| 20..0		disp	|
+-----------------------+

Unconditional Branch

    BxR	Ra.wq,disp.al		!Branch Format

    { update PC }
    Ra 	<- PC
    PC	<- PC + ( 4 * SEXT(disp))

    BR	Unconditional Branch
    BSR	Branch to Subroutine

Note: Difference between BR and BSR is branch prediction hints.

    BR	predicted as branch (no push)
    BSR	predicted as call   (push return address in branch prediction
                     stack)

    BR	30
    BSR	34

Alpha Memory Format
+-----------------------+
| 31..26	Opcode	|
| 25..21	Ra	|
| 20..16	Rb	|
| 15..0		mdisp	|
+-----------------------+

Jumps
    JMP	Ra.wq,(Rb.ab),hint	!Memory Format
    JSR	Ra.wq,(Rb.ab),hint	!Memory Format
    RET	Ra.wq,(Rb.ab),hint	!Memory Format
    JSR_COROUTINE	Ra.wq,(Rb.ab),hint	!Memory Format

    { update PC }
    va <- Rbv AND (NOT 3)
    Ra <- PC
    PC <- va

Note:	All jumps instructions have different branch predictions:

disp<15..14>	Meaning		Predict. Target		Predict Stack Actions
00		JMP		PC+{4*disp<13..0>	-----
01		JSR		PC+{4*disp<13..0>	Push PC
10		RET		Prediction stack	Pop
11		JSR_COROUTINE	Prediction stack	Pop, Push PC

    JMP			1A.0
    JSR			1A.1
    RET			1A.2
    JSR_COROUTINE		1A.3

HP-PA

+---------------------------+
|	Len	Value       |
|	6	3A          |
|	5	t           |
|	5	w1          |
|	3	xx	    |
|	11	w2          |
|	1	n           |
|	1	w	    |
+---------------------------+

Command				xx
BL,n		target,t	0	Branch and Link

    disp <- lshift(sign_ext({w1,w2,w}),2)
    IAQQ_Next <- IAQQ_Front + disp +8
    GR[t] <- IAQQ_Back + 4
    if (n) PSW[N] <- 1

GATE,n		target,t	1	Gateway (to more priviledge level)

+---------------------------+
|	Len	Value       |
|	6	3A          |
|	5	t           |
|	5	x           |
|	3	xx	    |
|	11	0           |
|	1	n           |
|	1	0	    |
+---------------------------+

                xx
BLR,n		x,t		2	Branch and Link Register

    IAQQ_Next <- IAQQ_Front + lshift(GR[x],3) + 8
    GR[t] <- IAQQ_Back + 4
    if (n) PSW[N] <- 1

Joined Commands:

                opcode
MOVB,cond,n	r1,r2,target	3A	Move and branch
MOVIB,cond,n	i,r,target	33	Move Immediate and branch

+---------------------------+
|	Len	Value       |
|	6	3A          |
|	5	b           |
|	5	x           |
|	3	xx	    |
|	11	0           |
|	1	n           |
|	1	0	    |
+---------------------------+

                xx
BV,n	x(b)			6	Branch Vectored

    IAQQ_Next{0..29} <- (GR[b] + lshift(GR[x],3)) {0..29}
    if (IAQQ_Front{30..31} < GR[b]{30..31})
        IAQQ_Next{30..31} <- GR[b]{30..31}
    else
        IAQQ_Next{30..31} <- IAQQ_Front{30..31}
    if (n) PSW[N] <- 1

+---------------------------+
|	Len	Value       |
|	6	opcode      |
|	5	b           |
|	5	w1          |
|	3	s	    |
|	11	w2          |
|	1	n           |
|	1	w	    |
+---------------------------+

            opcode
BE,n	wd(sr,b)	38		Branch External (to another space)
BLE,n	wd(sr,b)	39		Branch and Link External

Note:	Return from subroutine usually performed by
    BV or BE

MIPS

+-------------------------------+
|	Len	Value		|
|	6	Opcode		|
|	26	idx		|
+-------------------------------+

Command			Opcode		Description
J	target		0000 10		Jump

    PC <- {PC{GPRLEN..28},idx,00b}

JAL	target		0000 11		Jump and Link

    GPR[31] <- PC + 8
    PC <- {PC{GPRLEN..28},idx,00b}

+-------------------------------+
|	Len	Value		|
|	6	0 = SPECIAL	|
|	5	rs		|
|	5	0		|
|	5	rd		|
|	5	0		|
|	5	xx		|
+-------------------------------+

Command			xx	Description
JARL 	rd,rs 		001001	Jump and Link Register
JARL	rs		------	(rd = 31 implied)

    temp    <- GPR[rs]
    GPR[rd] <- PC + 8
    PC      <- temp

+-------------------------------+
|	Len	Value		|
|	6	0 = SPECIAL	|
|	5	rs		|
|	15	0		|
|	5	xx		|
+-------------------------------+

Command			xx	Description
JR	rs		001000	Jump Register

    PC	<- GPR[rs]

PowerPC

0..5	18
6..29	LI
30	AA
31	LK
            AA	LK
b	target		0	0		Branch
ba	target		1	0
bl	target		0	1
bla	target		1	1

    if AA 	{  	NIA <- sign_ext(LI * 4)		 }
    else	{	NIA <- CIA + sign_extend(li * 4) }
    if LK	{	LR  <- CIA + 4			 }

68K

Code			Size	Mnemonic		Description
01100000<-Disp->	B,W	BRA	ds		PC + Disp -> PC
01100001<-Disp->	B,W	BSR	ds		PC -> -(SP)
                            PC + Disp -> PC

0100111011<-EA->	--	JMP			 -> PC
0100111010<-EA->	--	JSR			PC -> -(SP)
                             -> PC

4E75			--	RTS			(SP) + -> PC

0100111001010nnn	W	LINK	An,ds		An -> -(SP)
<---Disp------->					SP -> An
                            SP + Disp -> SP

0100111001011nnn	-	UNLK	An		An -> SP
                            (SP)+ -> An

Z80

Operation		Description			Code
CALL	nn		PUSH	PC			CD nn nn
            PC <- nn

JP	nn		PC <- nn			C3 nn nn
JP	(HL)		PC <- HL			E9
JP	(ii)		PC <- ii			ii E9

JR	e		PC <- PC + e			18 ee

RET			POP	PC			C9

X86

    (Call Procedure) ==================
CALL	rel16			E8 cw
CALL	r/m16			FF /2
CALL	ptr16:16		9A cd		FAR
CALL	m16:16			FF /3		FAR
CALL	rel32			E8 cd
CALL	r/m32			FF /2
CALL	ptr16:32		9A cp		FAR
CALL	m16:32			FF /3		FAR

NEAR:
    PUSH	IP
    if (rel)
        IP <- IP + sign_extend(rel)
    else
        IP <-  src

Note: 	Far additionally push CS, then load CS.

    (Jump)	=============================
JMP	rel8			EB cb
JMP	rel16			E9 cw
JMP	r/m16			FF /4
JMP	ptr16:16		EA cd		FAR
JMP	m16:16			FF /5		FAR
JMP	rel32			E9 cd
JMP	r/m32			FF /4
JMP	ptr16:32		EA cp		FAR
JMP	m16:32			FF /5		FAR

NEAR:
    if (rel)
        IP <- IP + sign_extend(rel)
    else
        IP <- src

    (Return) =============================
RET				C3
RET				CB		FAR
RET	imm16			C2 iw
RET	imm16			CA iw		FAR

    POP	IP
    SP	<- SP + imm16		// if imm16 present

Note:	FAR also load CS

    (Make Stack Frame for Procedure Parameters) =======
ENTER imm16,imm8		C8 iw ib

Note:   we not interestion of level of ENTER <> 0

    PUSH	(E)BP		|  repeat  imm8 times
    MOV	E(BP),SP	|	(INCORRECT)
    SUB	E(SP),imm16

    (High Level Procedure Exit) =============
LEAVE				C9

    (E)SP <- (E)BP
    POP	(E)BP

IA64

Format B3
------------
40..37	5
36	S
35	d
34..33	wh
32..13	imm20d
12	p
11..9	---
8..6	b1
5..0	qp
--------------

br.call{.bhw.ph.dh} b1=target25		B3		Direct Call

Format  B4
--------------
40..37	0
36	--
35	d
34..33	wh
32..27	x6
26..16	--
15..13	b2
12	p
11..9	--
8..6	btype
5..0	qp
----------------

br.ret{.bhw.ph.dh}	b2		B4		Indirect Branch
                            (Return)

Format B5
---------------
40..37	1
36	--
35	d
34..32	wh
31..16	--
15..13	b2
12	p
11..9	--
8..6	b1
5..0	qp
----------------

br.call{.bwh.ph.dh}	b1=b2		B5		Indirect Call

JVM

GOTO	label		A7
GOTO_W	label		C8

JSR	label		A8
JSR_W	label		C9

ARETURN			B0
DRETURN			AF
FRETURN			AE
IRETURN			AC
LRETURN			AD
RETURN			B1
RET	 n		A9

LOOKUPSWITCH  !!complex!!	AB
TABLESWITCH   !!complex!!	AA

MCS51

ACALL	addr11		aaa1 0001 		PC <- PC + 2
                        PUSH	PC
                        PC(10..0) <- addr11

LCALL	addr16		0001 0010  	PC <- PC + 3
                        PUSH	PC
                        PC <- addr16

RET			0010 0010		POP	PC

AJMP	addr11		aaa0 0001 		PC(10..0) <- addr11

LJMP	addr16		0000 0010  	PC <- addr16

SJMP	rel		1000 0000 		PC <- PC + 2
                        PC <- PC + rel

JMP	@A+DPTR		0111 0011		PC <- A + DPTR


35.3.8 INTEGER CONDITIONAL MOVES AND SETS INSTRUCTIONS

    Here described next types of operations

    o	Conditional Sets
    o	Conditional Moves

SPARC

SPARC format 4
+-----------------------+------------------------+
| 31..30	10      | 31..30	10	 |
| 29..25	rd	| 29..25	rd       |
| 24..19	op3	| 24..19	op3      |
| 18		cc2	| 18		cc2	 |
| 17..14	cond	| 17..14	cond	 |
| 13		0	| 13		1        |
| 12		cc1	| 12		cc1	 |
| 11		cc0	| 11		cc0	 |
| 10..5		---	| 10..0		simm11   |
| 4..0		rs2	|	                 |
+-----------------------+------------------------+

    cc2 cc1 cc0	Conditional code
    1   0    0	icc
    1   1    0      xcc

Opcode		Op3	cond		Operation
mova		101100	1000		Move Always
movn		101100	0000		Move Never
movne		101100	1001		Move if Not Equal
move		101100	0001		Move if Equal
movg		101100	1010		Move if Greater
movle		101100  0010		Move if Less or Equal
movge		101100	1011		Move if Greater or Equal
movl		101100  0011		Move if Less
movgu		101100  1100		Move if Greater Unsigned
movleu		101100  0100		Move if Less or Equal Unsigned
movcc		101100  1101		Move if Carry Clear (Greater Equal Unsg)
movcs		101100  0101		Move if Carry Set (Less Unsigned)
movpos		101100  1110		Move if Positive
movneg		101100  0110		Move if Negative
movvc		101100  1111		Move if Overflow Clear
movvs		101100  0111		Move if Overflow Set

    A		1
    N		0
    NE		not Z
    E		Z
    G		not (Z or (N xor V))
    LE		Z or (N xor V)
    GE		not (N xor V)
    L		N xor V
    GU		not (C or Z)
    LEU		(C or Z)
    CC		not C
    CS		C
    POS		not N
    NEG		N
    VC		not V
    VS		V

ops	i_or_x_cc,reg(rs2),reg(rd)
ops	i_or_x_cc,imm11,reg(rd)

    if (condition)
    {
        r[rs2] -> r[rd]			// Non Immediate
        sign_extend(simm11) -> r[rd]	// Immediate
    }

Synonims:
    movne		movnz
    move		movz
    movcc		movgeu
    movcs		movlu

SPARC format 3
+-----------------------+------------------------+
| 31..30	10      | 31..30	10	 |
| 29..25	rd	| 29..25	rd       |
| 24..19	op3	| 24..19	op3      |
| 18..14	rs1	| 18..14	rs1	 |
| 13		0	| 13		1        |
| 12..10	rcond	| 12..10	rcond	 |
| 9..5		---	| 9..0		simm10   |
| 4..0		rs2	|	                 |
+-----------------------+------------------------+

Opcode		Op3	cond	Operation			Condition
movrz		101111	001	Move if Register Zero		r[rs1] == 0
movrlez		101111  010	Move if Register <= 0		r[rs1] <= 0
movrlz		101111  011	Move if Register <  0		r[rs1] <  0
movrnz		101111  101	Move if Register != 0		r[rs1] != 0
movrgz		101111  110	Move if Register >  0		r[rs1] >  0
movrgez		101111  111	Move if Register >= 0		r[rs1] >= 0

    if (condition)
    {
        r[rs2] -> r[rd]			// Not Immediate
        sign_ext(simm10) -> r[rd]	// Immediate
    }

Synonims:
    movrne		movrnz
    movre		movrz

ALPHA

Alpha Operate Format
+-------------------------+------------------------+
| 31..26	Opcode	  | 31..26	Opcode	   |
| 25..21	Ra	  | 25..21	Ra	   |
| 20..16	Rb	  | 20..13	LIT        |
| 15..13	SBZ	  | 12		1          |
| 12		0	  | 11..5	Function   |
| 11..5		Function  | 4..0	Rc         |
| 4..0		Rc        |                        |
+-------------------------+------------------------+

Conditional Move Integer
    CMOVxx	Ra.rq,Rb.rq,Rc.wq	!Operate Format
    CMOVxx	Ra.rq,#b.ib,Rc.wq	!Operate Format

CMOVEQ		Conditional Move if Register Equal to Zero
CMOVGE		Conditional Move if Register Greater than or Equal to zero
CMOVGT		Conditional Move if Register Greater than zero
CMOVLBC		Conditional Move if Low Bit Clear
CMOVLBS		Conditional Move if Low Bit Set
CMOVLE		Conditional Move if Register Less than equal to zero
CMOVLT		Conditional Move if Register Less than zero
CMOVNE		Conditional Move if Register Not Equal to zero

    if TEST(Rav, Condition_based_on_opcode) THEN
        Rc <- Rbv

    CMOVEQ		11.24
    CMOVGE		11.46
    CMOVGT		11.66
    CMOVLBC		11.16
    CMOVLBS		11.14
    CMOVLE		11.64
    CMOVLT		11.44
    CMOVNE		11.26

HP-PA

HP-PA is architecture have No conditional MOVES.
But we can produce it using complex code sequence by ourselfs.

MIPS

+------------------------------+
|	Len	Value
|	6	0
|	5	rs
|	5	rt
|	5	rd
|	5	0
|	5	xx
+------------------------------+

Command			xx
MOVN	rd,rs,rt	00 1011		Move Conditional on Not Zero
MOVZ	rd,rs,rt	00 1010		Move Conditional on Zero

            cond
    N		GRP[rt] != 0
    Z		GPR[rt] == 0

    if (cond)
    {
        GPR[rd] <- GPR[rs]
    }

SLT	rd,rs,rt	10 1010		Set on Less that
SLTU	rd,rs,rt	10 1011		Set on Less that Unsigned

            cond
    LT		GRP[rs] < GPR[rt]		[Signed]
    LTU		GPR[rs] < GPR[rt]		[Unsigned]

    if (cond)
    {
        GPR[rd] <- 1
    } else	GPR[rd] <- 0

+------------------------------+
|	Len	Value
|	6	xx
|	5	rs
|	5	rt
|	16	imm
+------------------------------+

Command			xx
SLTI	rt,rs,imm	00 1010	Set on Less That Immediate
SLTIU	rt,rs,imm	00 1011	Set on Less That Immediate Unsigned

    LTI	GPR[rs] < sign_extend(imm)		[Signed]
    LTIU	GPR[rs] < sign_extend(imm)		[Unsigned]

    if (cond)
    {
        GPR[rd] <-  1
    } else	GPR[rs] <-  0

PowerPC

Move on Power PC is 	'or  rs,rs,rd' for example...
None conditional moves exist on Power PC Architecture.
Need complex code with branches.

68K

Code			Size	Mnemonic		Description
0101cccc11<-EA->	B	Scc 		if (cc)
                               1 ->
                            else
                               0 ->
        Conditional Set on
0000	F	False			0
0001	T	True			1
0010	HI	High			Z'C'
0011	LS	Low or Same		Z+C
0100	CC	Carry Clear		C'
0101	CS	Carry Set		S'
0110	NE	Not Equal		Z'
0111	EQ	Equal			Z
1000	VC	Overflow Clear		V'
1001	VS	Overflow Set		V
1010	PL	Plus			N'
1011	MI	Minus			N
1100	GE	Greater or Equal	NV+N'V'
1101	LT	Less than		NV'+N'V
1110	GT	Greater than		NZ'V+N'Z'V'
1111	LE	Less or Equal		Z+NV+N'V'

Z80

None Exist, need to code for support.

X86

SETA	r/m8			0F	97
SETAE	r/m8			0F	93
SETB	r/m8			0F	92
SETBE	r/m8			0F	96
SETC	r/m8			0F	92
SETE	r/m8			0F	94
SETG	r/m8			0F	9F
SETGE	r/m8			0F	9D
SETL	r/m8			0F	9C
SETLE	r/m8			0F	9E
SETNA	r/m8			0F	96
SETNAE	r/m8			0F	92
SETNB	r/m8			0F	93
SETNBE	r/m8			0F	97
SETNC	r/m8			0F	93
SETNE	r/m8			0F	95
SETNG	r/m8			0F	9E
SETNGE	r/m8			0F	9C
SETNL	r/m8			0F	9D
SETNLE	r/m8			0F	9F
SETNO	r/m8			0F	91
SETNP	r/m8			0F	9B
SETNS	r/m8			0F	99
SETNZ	r/m8			0F	95
SETO	r/m8			0F	90
SETP	r/m8			0F	9A
SETPE	r/m8			0F	9A
SETPO	r/m8			0F	9B
SETS	r/m8			0F	98
SETZ	r/m8			0F	94

    if (cond)
    {
        r/m <- 1
    } else	r/m <- 0

(Pentium Pro+)
CMOVcc	r16,r/m16		0F 0100cccc	Postbyte
CMOVcc	r16,r/m32		0F 0100cccc	Postbyte

    if (cond)
    {
        r <- r/m
    }

IA64

Every Instruction have Qp - qulifying predecate

Mov  is:    or 	DEST=SRC,r0

JVM

LCMP		Compare Longs		94

Integer compares  are branches. Conditional move and sets are
superposition of load and branches.

MCS51

No such instructions support in pure small 8-bit microcontroller.


35.3.9 INTEGER BITS AND BITSTRINGS INSTRUCTIONS

    Here is placed next types of CPUs instructions

    o	Bit Test
    o	Bit Set/Reset/Complement
    o	Population Count
    o	Count Leading/Trailing Zeroes
    o	Extract/Deposit/Zero and Deposit

SPARC

SPARC format 3
+-----------------------+------------------------+
| 31..30	10      | 31..30	10	 |
| 29..25	rd	| 29..25	rd       |
| 24..19	op3	| 24..19	op3      |
| 18..14	0s	| 18..14	0s       |
| 13		0	| 13		1        |
| 12..5		---	| 12..0		simm13   |
| 4..0		rs2	|	                 |
+-----------------------+------------------------+

    Opcode		Op3		Operation
    popc		10 1110		Population Count

popc	reg(rs2),reg(rd)
popc	simm13,reg(rd)

        r[rd] <- number of one bits in r[rs2]
             or in sign_extend(simm13)

ALPHA

Alpha Operate Format
+-------------------------+------------------------+
| 31..26	Opcode	  | 31..26	Opcode	   |
| 25..21	Ra	  | 25..21	Ra	   |
| 20..16	Rb	  | 20..13	LIT        |
| 15..13	SBZ	  | 12		1          |
| 12		0	  | 11..5	Function   |
| 11..5		Function  | 4..0	Rc         |
| 4..0		Rc        |                        |
+-------------------------+------------------------+

Count Leading Zeroes
    CTLZ	Rb.rq,Rc.wq		!Operate Format

    temp = 0
    FOR i FROM 63 DOWN TO 0
        if { Rbv EQ 1) THEN BREAK
        temp = temp + 1
    END
    Rc<6..0>  <- temp<6..0>
    Rc<63..7> <- 0

    CTLZ	1C.32

    (Ra must be R31)

    // ----------------------------------------------------------

Count Population

    CTPOP	Rb.rq,Rc.wq		!Operate Format

    temp = 0
    FOR i FROM 63 DOWN TO 0
        if { Rbv EQ 1) THEN 	temp = temp + 1
    END
    Rc<6..0>  <- temp<6..0>
    Rc<63..7> <- 0

    CTPOP	1C.30

    (Ra must be R31)

    // ----------------------------------------------------------

Count Trailing Zero

    CTTZ	Rb.rq,Rc.wq		!Operate Format

    temp = 0
    FOR i FROM 0  TO 63
        if { Rbv EQ 1) THEN 	BREAK
        temp = temp + 1
    END
    Rc<6..0>  <- temp<6..0>
    Rc<63..7> <- 0

    CTTZ	1C.33

    (Ra must be R31)

HP-PA

Do not forget:
    BB,cond,n	r,p,target	Branch on Bit
    BVB,cond,n	r,target	Branch on Variable Bit

Read Extract operation in SHIFT/ROTATES section for HP-PA

+---------------------------+
|	Len	Value       |
|	6	35          |
|	5	t           |
|	5	r  or im5   |
|	3	c	    |
|	3	xx          |
|	5	0 or p      |
|	5	len	    |
+---------------------------+

Command				xx
VDEP,cond	r,len,t		1	Variable Deposit
DEP,cond	r,p,len,t	3	Deposit
VDEPI,cond	im,len,t	5	Variable Deposit Immediate
DEPI,cond	im,p,len,t	7	Deposit Immediate
ZVDEP,cond	r,len,t		0	Zero and Variable Deposit
ZDEP,cond	r,p,len,t	2	Zero and Deposite
ZVDEPI,cond	r,p,len,t	4	Zero and Variable Deposite Immediate
ZDEPI,cond	i,p,len,t	6	Zero and Deposite Immediate

MIPS

None Bit/Bit strings operations on MIPS exist.
Use superposition of Shifts/Logical instructions instead.

PowerPC

0..5	opcode1
6..10	S
11..15	A
16..20	0s
21.30	opcode2
31	Rc

            Rc		opcode
cntlzw	rA,rS		0		31.26	Count Leading Zeroes Word
cntlzw.	rA,rS		1

        n <- 0
        do while n < 32
            if rS[n] = 1 then leave
            n <- n + 1
        enddo
        rA <- n

0..5	opcode1
6..10	S
11..15	A
16..20	SH		B
21..25	MB
26..30	ME
31	Rc

                Rc	opcode
rlwimi	rA,rS,SH,MB,ME		0	20	Rotate Left Word Immediate
rlwimi.	rA,rS,SH,MB,ME		1		then Mask Insert

    n <- SH
    r <- ROTL(rS,n)
    m <- MASK(MB,ME)
    rA <- (r AND m) OR (rA AND (NOT m))

rlwinm	rA,rS,SH,MB,ME		0	21	Rotate Left Word Immediate
rlwinm.	rA,rS,SH,MB,ME		1		then AND with Mask

    n <- SH
    r <- ROTL(rS,n)
    m <- MASK(MB,ME)
    rA <- r AND m

rlwnm	rA,rS,rB,MB,ME		0	23	Rotate Left Word then AND
rlwnm.	rA,rS,rB,MB,ME		1		with Mask

    n <- rB[27..31]
    r <- ROTL(rS,n)
    m <- MASK(MB,ME)
    rA <- r AND m

68K

Code			Size	Mnemonic		Description
0000xxx101<-EA->	B,L	BCHG  Dx,		NOT bit(EA) -> Z
0000100000<-EA->		BCHG  #x,		XOR bit(EA)

0000xxx110<-EA->	B,L	BCLR  Dx,		NOT bit(EA) -> Z
0000100010<-EA->		BCLR  #x,		0 -> bit(EA)

0000xxx111<-EA->	B,L	BSET  Dx,		NOT bit(EA) -> Z
0000100011<-EA->		BSET  #x,		1 -> bit(EA)

0000xxx100<-EA->	B,L	BTST  Dx,		NOT bit(EA) -> Z
0000100000<-EA->		BTST  #x,

Since 68020 new group of commands for work with bit fields

    BFCHG	 {Of:Wf}
    BFCLR	 {Of:Wf}
    BFSET	 {Of:Wf}
    BFTST	 {Of:Wf}
    BFEXTS	 {Of:Wf},Dn
    BFEXTU	 {Of:Wf},Dn
    BFINS	Dn,  {Of:Wf}
    BFFFO	 {Of:Wf}, Dn

Z80

Operation		Description			Code
BIT	b,r		Z <- NOT r[b]		CB 40+b*8+r
BIT	b,(ii+n)				ii CB nn 40+b*8+6

RES	b,r		0 -> r[b]		CB C0+b*8+r
RES	b,(ii+n)				ii CB nn C0+b*8+6

SET	b,r		1 -> r[b]		CB 80+b*8+r
SET	b,(ii+n)				ii CB nn 80+b*8+6

X86

    (Bit Scan Forward) ===============
BSF	r16,r/m16		0F BC
BSF	r32,r/m32		0F BC

    if r/m = 0
    {
        ZF <- 1
        r  <- Undefined
    } else
    {
        temp <- 0
        ZF <-  0
        while bite[r/m,temp] = 0
        DO
            temp <- temp + 1
            r <- temp
        OD
    }

    (Bit Scan Reverse) ===============
BSF	r16,r/m16		0F BD
BSF	r32,r/m32		0F BD

    if r/m = 0
    {
        ZF <- 1
        r  <- Undefined
    } else
    {
        temp <- OperandSize - 1
        ZF <-  0
        while bite[r/m,temp] = 0
        DO
            temp <- temp - 1
            r <- temp
        OD
    }

    (Bit Test) =========================
BT	r/m16,r16		0F A3
BT	r/m32,r32		0F A3
BT	r/m16,i8		0F BA /4 ib
BT	r/m32,i8		0F BA /4 ib

    CF <- BIT[r/m,r/i]

    (Bit Test and Complement) ==============
BTC	r/m16,r16		0F BB
BTC	r/m32,r32		0F BB
BTC	r/m16,i8		0F BA /7 ib
BTC	r/m32,i8		0F BA /7 ib

    CF <- BIT[r/m,r/i]
    BIT[r/m,r/i] <- NOT BIT[r/m,r/i]

    (Bit Test and Reset) ==============
BTR	r/m16,r16		0F B3
BTR	r/m32,r32		0F B3
BTR	r/m16,i8		0F BA /6 ib
BTR	r/m32,i8		0F BA /6 ib

    CF <- BIT[r/m,r/i]
    BIT[r/m,r/i] <- 0

    (Bit Test and Set) ==============
BTS	r/m16,r16		0F AB
BTS	r/m32,r32		0F AB
BTS	r/m16,i8		0F BA /5 ib
BTS	r/m32,i8		0F BA /5 ib

    CF <- BIT[r/m,r/i]
    BIT[r/m,r/i] <- 1

Note: Use SHLD,SHRD for Extract Bitstrings

IA64

Format I9
-----------
40..37	7
36	Za
35..34	Z2a
33	Zb
32	Ve
31..30	X2c	Opcode = 7.Za.Zb.Ve.Z2a.X2b.X2c
29..28	X2b
27	--
26..20	r3
19..13	0
12..6	r1
5..0	qp
------------

popcnt		r1=r3		I9	7.0.1.0.1.1.2	Population count

Format I11
-----------
40..37	5
36	--
35..34	X2
33	X
32..27	Len6d
26..20	r3		Opcode = 5.x2.x.y
19..14	Pos6b
13	y
12..6	r1
5..0	qp
------------

extr.u		r1=r3,pos6,len6	I11	5.1.0.0		Extract
extr		r1=r3,pos6,len6	I11	5.1.0.1

Format I12
-----------
40..37	5
36	--
35..34	X2
33	X
32..27	Len6d
26	y
25..20	cpos6c		Opcode = 5.x2.x.y
19..13	r2
12..6	r1
5..0	qp
------------

dep.z		r1=r2,pos6,len6	I12	5.1.1.0		Zero and Extract

Format I13
-----------
40..37	5
36	s
35..34	X2
33	X
32..27	Len6d
26	y
25..20	cpos6c		Opcode = 5.x2.x.y
19..13	imm7b
12..6	r1
5..0	qp
------------

dep.z		r1=imm8,pos6,len6  I13	5.1.1.1		Zero and Deposit
                            Immediate

Format I14
-----------
40..37	5
36	s
35..34	X2
33	X
32..27	Len6d
26..20	r3
19..14	cpos6c		Opcode = 5.x2.x
13	--
12..6	r1
5..0	qp
------------

dep	r1=imm1,r3,pos6,len6	I14	5.3.1	Deposit Immediate

Format I15
-----------
40..37	4
36..31	cpos6d
30..27	len4d
26..20	r3
19..13	r2		Opcode = 4
12..6	r1
5..0	qp
------------

dep	r1=r2,r3,pos6,len4	I15	4	Deposit

Format I16
-----------
40..37	5
36	tb
35..34	x2
33	ta
32..27	p2		Opcode: 5.x2.ta.tb.y.c
26..20	r3
19..14	pos6b
13	y
12	c
11..6	p1
5..0	qp
-------------

tbit.z		  p1,p2=r3,pos6	I16	5.0.0.0.0.0	Test Bit
tbit.z.unc	  p1,p2=r3,pos6	I16	5.0.0.0.0.1
tbit.z.and	  p1,p2=r3,pos6 I16	5.0.0.1.0.0
tbit.nz.and	  p1,p2=r3,pos6	I16	5.0.0.1.0.1
tbit.z.or	  p1,p2=r3,pos6	I16	5.0.1.0.0.0
tbit.nz.or	  p1,p2=r3,pos6	I16	5.0.1.0.0.1
tbit.z.or.andcm   p1,p2=r3,pos6	I16	5.0.1.1.0.0
tbit.nz.or.andcm  p1,p2=r3,pos6	I16	5.0.1.1.0.1

Format I29
-----------
40..37	0
36	--
35..33	x3
32..27	x6
26..20	r3	Opcode = 0.x3.x6
19..13	--
12..6	r1
5..0	qp
-------------

czx1.l		r1=r3		I29	0.0.18	Compute Zero Index Left
czx2.l		r1=r3		I29	0.0.19

czx1.r		r1=r3		I29	0.0.1C	Compute Zero Index Right
czx2.r		r1=r3		I29	0.0.1D

JVM

None special instrucions for Integer Bits and Bits strings exist on
JVM (because Java language not support bit strings).

But needed routines may be performed used superpositions of
Shifts/Logical operations.

MCS51

JNB	bit,rel		0011 0000  	Branch if bit is clear
JB	bit,rel		0010 0000     Branch if bit is set
JBC	bit,rel		0001 0000     Branch if bit is set
                        and clear bit

CLR	bit		1100 0010 		Clear Bit
SETB	bit		1101 0010 		Set Bit
CPL	bit		1011 0010 		Complement Bit

MOV	C,bit		1010 0010 		Move Bit to Carry
MOV	bit,C		1001 0010 		Move Carry to Bit


40. ПРЕДСТАВЛЕНИЕ ВЕЩЕСТВЕННЫХ ЧИСЕЛ

THIS SECTION IS UNDER CONSTRUCTION


40.1. ЧИСЛА С ПЛАВАЮЩЕЙ ТОЧКОЙ

IEEE 754-1985 стандарт на числа с плавающей точкой
(87,287,387 original не соответствуют стандарту)

FP Number имеет формат:

    +-+-------+----------+
    |S|  E    |    M     |
    +-+-------+----------+

S - Sign если = 0 то число положительное, если = 1 то число отрицательное
E - Exponent - смещенная экспонента.
        ....
        2**(-1) = N - 1
        2** 0   = N		, где N - смещение порядка
        2** 1   = N + 1		 (зависит от размера мантиссы)
        ...
M - Mantiss  - мантисса
           в обычном случае нормализованная (т.е. старший бит
           не записывается и равен 1.
           [точка справа старшего бита мантиссы]

Число = (-1)^S * 2^(E-N) * 1.MMMMMMMMM, где MMMMMMM - биты мантиссы

         1.MMMMMMMMMM  <- неявная нормализация
    +-+-------+----------+
    |S|  E    |    M     |
    +-+-------+----------+

Иногда при предельных значениях порядка неявная нормализация теряется и
числа становятся денормализированными.

  Single

Single занимает 32-бит (DWORD)

К сожалению FP в памяти тоже подвержены endian.

Single Big-Endian:
    ----------------------------------------
    byte	bits	description
    ----------------------------------------
    0	0-6	exponent bits 1-7
        7	sign
    1	0-6	mantissa bits 16-22
        7	exponent bit 0
    2	0-7	mantissa bits 8-15
    3	0-7	mantissa bits 0-7
    ----------------------------------------

Single Little-endian:
    ----------------------------------------
    byte	bits	description
    ----------------------------------------
    0	0-7	mantissa bits 0-7
    1	0-7	mantissa bits 8-15
    2	0-6	mantissa bits 16-22
        7	exponent bit 0
    3	0-6	exponent bit 1-7
        7	sign
    ----------------------------------------

  Double

Double занимает 64-бит (QWORD)

Double big-endian:
    ----------------------------------------
    byte	bits	description
    ----------------------------------------
    0	0-6	exponent 4-10
        7	sign
    1	0-3	mantissa 48-51
        4-7	exponent 0-3
    2	0-7	mantissa 40-47
    3	0-7	mantissa 32-39
    4	0-7	mantissa 24-31
    5	0-7	mantissa 16-23
    6	0-7	mantissa 8-15
    7	0-7	mantissa 0-7
    ----------------------------------------

Double little-endian:
    ----------------------------------------
    byte	bits	description
    ----------------------------------------
    0	0-7	mantissa 0-7
    1	0-7	mantissa 8-15
    2	0-7	mantissa 16-23
    3	0-7	mantissa 24-31
    4	0-7	mantissa 32-39
    5	0-7	mantissa 40-47
    6	0-3	mantissa 48-51
        4-7	exponent 0-3
    7	0-6	exponent 4-10
        7	sign
    ----------------------------------------

  Quad

Quad занимает 128-бит (OWORD)

Соответсвенно endian.

  Extended (Intel)

Extended - платформо-зависимый, занимает на Intel 80-бит (TBYTE)
Поскольку Intel то Little-endian.

  Параметры FP

     -------------------------------------------------------------
            Single	Double	Extended Quad
    -------------------------------------------------------------
    Len bits	32	64	80	128
    M   bits	24*	53*	64	113*
    E   bits	8	11	15	15
    E   max		+127	+1023	+16383	+16383
    E   min		-126	-1022	-16382	-16382
    N		127	1023	16383	16383
    -------------------------------------------------------------

    1.188 * 10^-38	  < 	| Single |  	< 3.40 * 10^38
    2.23  * 10^-308   <	| Double |	< 1.79 * 10^308
    3.37  * 10^-4932  <	|  Quad  |	< 1.18 * 10^4932

    log{2}(10) ~= 3.3 двоичных разряда на десятичную цифру

    Мантисса длинной 20 (для примера) бит держит 20/3.3 = 6.06 десятичных
    цифр

  Специальные числа

0:

0	имеет все биты равными нулю.

Бесконечность:

NaN:

  Денормализованные числа

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

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

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

        +-+-------+---------------+
    |S|00.. 00|000.........000|	0
    +-+-------+---------------+

    +-+-------+---------------+
    |S|00.. 00|     M         |	Denormalized number
    +-+-------+---------------+

Обычные числа трактуются как:

    (-1)^S * 2^(E-N) * 1.MMMMMMMM

    +-+--------+-----------------------+
    |0|00000001|00000000000000000000000|
    +-+--------+-----------------------+

        (-1)^0 * 2^(1-127) * 1.MMM  = 2^(-126) * 1.0000000000..

Денормализованные числа трактуются как:

    (-1)^S * 2^(E-N+1) * 0.MMMMMMMM

    Экспонента на самом деле равна не 0, а 1

    +-+--------+-----------------------+
    |0|00000000|11111111111111111111111|
    +-+--------+-----------------------+

        (-1)^0 * 2^(0-127+1) * 0.MMMM = 2^(-126) * 0.111111111..

  Примеры FP

Single
    -infinity	FF80 0000
    -2		C000 0000
    -1		BF80 0000
    -0.5		BF00 0000
    -0.0		8000 0000
    +0.0		0000 0000
            0000 0001	minimal demormalized positive
            007F FFFF	maximal denormalized positive
    0.5		3F00 0000
    1		3F80 0000
    2		4000 0000
    3		4040 0000
    4		4080 0000
    5		40A0 0000
    6		40C0 0000
    7		40E0 0000
    8		4100 0000
    9		4110 0000
    10		4120 0000
    15		4170 0000
    16		4180 0000
    2^24		4B80 0000
    2^31		4F00 0000
    2^32		4F80 0000
    2^64		5F80 0000
            7F7F FFFF	maximal normalized
    +infinity	7F80 0000
            7F80 0001	minimal SNaN
            7FBF FFFF	maximal SNaN
            7FC0 0000	minimal QNaN
            7FFF FFFF	maximal QNaN

Double
    -infinity	FFF0 0000 0000 0000
    -2		C000 0000 0000 0000
    -1		BFF0 0000 0000 0000
    -0.5		BFE0 0000 0000 0000
    -0.0		8000 0000 0000 0000
    +0.0		0000 0000 0000 0000
            0000 0000 0000 0001   minimal denormalized positive
            000F FFFF FFFF FFFF   maximal denormalized positive
    0.5		3FE0 0000 0000 0000
    1		3FF0 0000 0000 0000
    2		4000 0000 0000 0000
    3		4008 0000 0000 0000
    4		4010 0000 0000 0000
    5		4014 0000 0000 0000
    6		4018 0000 0000 0000
    7		401C 0000 0000 0000
    8		4020 0000 0000 0000
    9		4022 0000 0000 0000
    10		4024 0000 0000 0000
    15 		402E 0000 0000 0000
    16		4030 0000 0000 0000
    2^24		4170 0000 0000 0000
    2^31		41E0 0000 0000 0000
    2^32		41F0 0000 0000 0000
    2^64		43F0 0000 0000 0000
            7FEF FFFF FFFF FFFF  maximal normalized
    +infinity	7FF0 0000 0000 0000
            7FF0 0000 0000 0001  minimal SNaN
            7FF7 FFFF FFFF FFFF  maximal SNaN
            7FF8 0000 0000 0000  minimal QNaN
            7FFF FFFF FFFF FFFF  maximal QNaN

    попробуем перевести  1.0:

        S = 0
        E = 0
        M = 1.000000

    S EEEE EEEE		MMM...MMMM
    0 0000 0000           1.000...0000
+	  0111 1111 = N
    ----------------------------------
    0 0111 1111		000...0000
    +---++---++---------------+...+--+
      3    F      8		   00s 0

        3F80 0000

  NaN

    NaN - Not a Number - не число - не представимое число
          которое может возникать во всяких специальных случаях
          типа:
            0 / 0
            корень квадратный (-1)

        NaN
          /    \
        SNaN   QNaN

    SNaN - signaled NaN - модуль FP никогда не создает такие числа
                  (используются для exceptions)
    QNaN - not signaled NaN - модуль FP может их создавать

    NaN не стандартизированны:

            PowerPC,x86:		high bit of M = 0  SNaN
                                  = 1  QNaN
            Alpha,HPPA,MIPS:	high bit of M = 0  QNaN
                                  = 1  SNaN

  Правила вычислений

x - нормальное представимое число (не 0, не infinity, не NaN)

    x		+	+infinity	=  +infinity
    x		-	+infinity	=  -infinity
    x		+	-infinity	=  -infinity
    x		-	-infinity	=  +infinity

    x		*	+infinity	=  +infinity
    x		/	+infinity	=  0	(знак зависит от x)

    +infinity	+	+infinity	= +infinity
    -infinity	+	-infinity	= -infinity
    -infinity	-	+infinity	= -infinity
    +infinity	-	-infinity	= +infinity

    +infinity	+	-infinity	= NaN
    -infinity	+	+infinity	= NaN
    +infinity	-	+infinity	= NaN
    -infinity	-	-infinity	= NaN

    0		*	infinity	= NaN
    0		/	0		= NaN
    infinity	/	infinity	= NaN
    x		MOD	0		= NaN
    infinity	MOD	x		= NaN
    квадратный корень(x)			= NaN (если x < 0)

    Любая операция с SNaN всегда дает NaN

  Числовая прямая

Используется аффинный (Affine) режим:

     -infinity        	     -0  +0	     		+infinity
    |           -x          |          +x            |
    |-----------------------|------------------------|

 -infinity                -0 +0                  -infinity
   |                        |                        |
   |---------|------|---|---|---|---|--------|-------|
        O       N     D   U   U   D     N       O

    O = Overlow Zone
    N = Normalized Zone
    D = Denormalized Zone
    U = Underflow Zone

Eще есть проективный режим но он не входит в IEEE 754
(ранние [до принятия стандарта IEEE754] сопроцессоры 87, 287 могли его
использовать)

    Аффинный	Проективный
    +0.0            0.0
    -0.0
    +infinity	infinity
    -infinity

  Режимы округления

    Округление к 0
    Округление к ближайшему
    Округление к +бесконечности
    Округление к -бесконечности

  Другие FP форматы:

Cray:
    Формат чисел с плавающей точкой на CRAY-1
    -----------------------
    Bits	Description
    -----------------------
    0	Sign
    1..15	Exponent
    16..63	Mantiss
    -----------------------

VAX:
    ---------------------------------------------------------------
    Number				BITS
    Type		exponent	fraction	total	N
    ---------------------------------------------------------------
    F float		8		23		32      128
    D float	        8		55		64      128
    G float		11		52		64      1024
    H float		15		112		128	16384
    ---------------------------------------------------------------

    тоже нормализованные (в отличии от IEEE 754 точка слева от скрытой
единицы). не поддерживает NaN и бесконечность.
Для всех VAX форматов мантисса нормализуется так чтобы 0.5 <= f < 1.0
MSB мантиссы - всегда 1 и не записывается.

F-Float:

    ----------------------------------------
    byte	bits	description
    ----------------------------------------
    0	0-6	mantissa bits 16-22
        7	exponent bit 0
    1	0-6	exponent bit 1-7
        7	sign bit
    2	0-7	mantissa bits 0-7
    3	0-7	mantissa bits 8-15
    ----------------------------------------

       0	00000000	(really Sign=0, Exponent=0, mantiss=don't care (VAX)
                 but for Alpha if mantiss != 0 it caused exception)
    +1.0	00004080	(mantiss = (.1)0, exponent = 129)
    +1.5	000040C0	(mantiss = (.1)1, exponent = 129)

D-float:
    ----------------------------------------
    byte	bits	description
    ----------------------------------------
    0	0-6	mantissa 48-54
        7	exponent 0
    1	0-6	exponent 1-7
        7	sign
    2	0-7	mantissa 32-39
    3	0-7	mantissa 40-47
    4	0-7	mantissa 16-23
    5	0-7	mantissa 24-31
    6	0-7	mantissa 0-7
    7	0-7	mantissa 8-16
    ----------------------------------------

G-float:
    ----------------------------------------
    byte	bits	description
    ----------------------------------------
    0	0-3	mantissa 48-51
        4-7	exponent 0-3
    1	0-6	exponent 4-10
        7	sign
    2	0-7	mantissa 32-39
    3	0-7	mantissa 40-47
    4	0-7	mantissa 16-23
    5	0-7	mantissa 24-31
    6	0-7	mantissa 0-7
    7	0-7	mantissa 8-15
    ----------------------------------------

Что значит точка слева от скрытой единицы:

IEEE754                         S    E               M
    1.0	=  1 * 2^0	0 01111111 (1.)00000000000000000000000
                     0
    1.0     =  3F000000
          MSB     LSB

VAX F float
    1.0     =  0.1 * 2^1	0 10000001 (.1)00000000000000000000000
                     1
    1.0     =  40800000
           но учитывая расположение в памяти получаем:
           00004080
          MSB     LSB

Во время 8-битных машин когда в микропроцессорах не был встроен блок операций
с плавающей точкой из MS-BASIC использовался тип для программных операций
с плавающей точкой (MSFLOAT).

MSFLOAT = REAL48

        MSB
    +-+----------------+-----+
    |S|      M         |  E  |
    +-+----------------+-----+
     1       39           8

В отличие от IEEE 754 имеет поменянные местами мантиссу и экспоненту.

Real48 тоже храниться нормализованным:

    N =  if E == 0, then	0
         if E != 0, then  (-1)^S * 2^(E-129) * (1.M)

    2.9   * 10^-39 < | Real | < 1.7*10^38


40.1.1. ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ТОЧКОЙ

Пусть
    X = Xs * B**Xe		Xs - мантисса и знак, Xe - экспонента
    Y = Ys * B**Ye		Ys - мантисса и знак, Ye - экспонента

Пусть Xe <= Ye, тогда

    X + Y = (Xs * B**(Xe-Ye) + Ys) * B**Ye
    X - Y = (Xs * B**(Xe-Ye) - Ys) * B**Ye
    X * Y = (Xs * Ys) * B**(Xe + Ye)
    X / Y = (Xs / Ys) * B**(Xe - Ye)

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

  сложение/вычитание

    C = A + B
        WE  = MAX(A.E, B.E)  	// берем максимальную экспоненту
        WAM = DENORMALIZE(A,WE) // денормализуем по нужной экспоненте
        WBM = DENORMALIZE(B,WE)
        NM  = WAM + WBM		// проверим CF
        if CF = 1
        {
            NE = WE + 1
        } else  {
            NE = WE
        }
        C.E = NE
        C.M = NM
        C.S = знак того кто больше

  умножение

    C = A * B
        C.E = A.E + B.E
        C.S = A.S + B.S		// по модулю 2
        C.M = DENORMALIZE(A.M) * DENORMALIZE(B.M)

  деление

    C = A / B
        C.E = A.E - B.E
        C.S = A.S + B.S		// по модулю 2
        C.M = DENORMALIZE(A.M) / DENORMALIZE(B.M)

  Квадратный корень

    Пусть есть число = S * p^k

тогда, если k - четное, то

    SQRT(S * p^k) = SQRT(S) * p^(k/2)

а если нечетное, то

    SQRT(S * p^k) = SQRT(S * p * p^(k-1)) = SQRT(S*p) * p^((k-1)/2)

Основы вычисления квадратного корня:

Идея:
    SQRT[Z] = SQRT[(A+B)^2] = SQRT[A^2 + 2AB + B^2]

Рассмотрим простой случай - корень из 3-4 значного числа:

      ______
     /    2
   \/(a+b)

      ____________
     / 2         2                                 _______
   \/ a + 2ab + b       	возьмем например \/ 150

      ____________
     / 2         2    				1.50
   \/ a + 2ab + b  = a                          1.00	a =  1 * 10 = 10
       2
     -a

      ____________
     / 2         2				1.50
   \/ a + 2ab + b  = a                          1.00
       2                                        ----
     -a                                           50 = 2ab + b^2
     ---     2
      2ab + b

                     2
разделим теперь 2ab+b  на 2а:

               2
        2ab + b     2ab
        -------- ~= --- ~= b		потому что a >> b
           2a       2a

таким образом мы узнаем b:			50 / 2a = 50 / 20 = 2...
                        значет следущая цифра это 2.

      ____________
     / 2         2
   \/ a + 2ab + b  = a + b
       2
     -a
     ---     2
      2ab + b
    - (2a + b) * b
     -------------
                 0

                    проверим:
                    12^2 = 144 < 150 < 169 = 13^2

Рассмотрим более сложный случай (корень из 5-6 значного числа):

      _______
     /      2
   \/(a+b+c)

   (a+b+c)*(a+b+c) = a^2 + ab + ac + ab + b^2 + bc + ac + bc + c^2 =
           = a^2 + 2ab + b^2 + 2ac + 2bc + c^2  =
           = a^2 + 2ab + b^2 + 2(a+b)*c + c^2

      ___________________________
     / 2         2              2
   \/ a + 2ab + b + 2(a+b)*c + c

по аналогии с случаем 3-4 значного числа:

      ___________________________
     / 2         2              2
   \/ a + 2ab + b + 2(a+b)*c + c
       2
     -a
     ---     2
      2ab + b
    - (2a + b) * b
     ------------------------------
                        2
            2(a+b)*c + c
           -(2(a+b) + c) *c
           ----------------
                  0

Проиллюстрируем:
    __________
  \/ 28.72.96
     25 	первая цифра пять - типа полный квадрат который влез
     ---
      3.72      372 = 2*5*b + b^2
      .         372/2a = 372/(2*5*10) = 372/100 = 3,.. (дробная часть неважна)
      .		  (10 - потому что 5 на 1 порядок старше)
      3.09      (2a+b)*b = (2*5*10 + 3)*3 = 103 * 3 = 109
        --------
        63.96   6696 = 2*(a+b)*c + c^2
        .        6696/[2(a+b)] = 6696/(2*(5*100 + 3*10) =  (5 на 2 порядка, 3 на порядок)
    .		      = 6696/(2*530) = 6696/1060 =  6,... (дробная часть неважна)
        .       (2(a+b)+c) * c =  (2*(500+30) + 6)*6 = 1066 * 6 =  6396
    63.96
        -----
        0

таким образом:
     ________
   \/ 287296   = 536

Специальные случаи которые могут возникать в десятичной системе.
    ____________
  \/ 3'25,80'25
     1
     ---	(случай 1)
     225	225 = 2ab + b^2
     .		225 / 2a = 225 / (2*1*10) = 225 / 20 = 11 (!)
     .		11 это уже больше чем цифра поэтому берем мах цифру = 9
     .
     .		(случай 2)
     .		(2ab + b^2) = (2*1*10 + 9) * 9 = 29 * 9 = 261 > 225 (!)
     .		значит 9 - это слишком большая цифра - поэтому берем 8
     224,	(2ab + b^2) = (2*1*10 + 8) * 8 = 28 * 8 = 224 < 225  Ok
     ------
        180 	180 = 2*(a+b)*c + c^2
    .	180 / 2(a+b) = 180 / 2*(1*100 + 8*10) = 180/2*(180) = 180/360=0,..
    000	цифра будет 0
        итд
        (кстати если будем пересекать десятичную точку то продолжаем
         считать частичный корень как целое число).

  _________
\/0,00'00'28
     .	  	(случай 3)
     .		лидирующие пары нули можно сразу писать в результат
     .		как 0 за каждую пару
  0,00'00    	Начало результата = 0,0
  ----------
      28
      25   	5
      ----
       300 	300/100 = 3, но 103*3 = 309 > 300, поэтому 2
           204         поэтому 2
       ----
        9600	9
        9441
            -----
        итд             результат примерно равен 0,00529

Аналогично для 7-8 значного и более старших чисел:

      _________         ___________________________________________
     /        2        / 2         2              2               2
   \/(a+b+c+d)   =   \/ a + 2ab + b + 2(a+b)*c + c + 2(a+b+c)d + d

   ___________         _____________________________________________________________
  /          2        / 2         2              2               2                 2
\/(a+b+c+d+e)   =   \/ a + 2ab + b + 2(a+b)*c + c + 2(a+b+c)d + d + 2(a+b+c+d)e + e

Вычисление квадратного корня в двоичной системе:
(оно самое простое так как нет сложных случаев)

      ____________
     / 2         2
   \/ a + 2ab + b  = a
       2
     -a
     ---     2
      2ab + b

Заметим что в двоичной системе у нас только 2 цифры 0 и 1
соответсвенно
               2
    2аb + b   может быть равно либо
        0	  если b = 0
        2a + 1	  если b = 1

           2
    2(a+b)c + c   может быть равно либо
        0	     если с = 0
            2(a+b) + 1   если с = 1
    итд

    заметим что:
        2a + 1 = (a << 1) + 1

    то есть если, a или a+b итд - число вида  xxxx
    то
                   2
        2ab + b   будет иметь вид xxxx01   если b = 1
        (сдвиг на 1 бит потому что a на порядок больше
         и еще на один потому что умножается на 2)

Пример:
          ___________
    \/ 1100010 {2}		надо вычислить

    01.10.00.10,		делим на группы по 2 цифры

                -----------------------------------------
                Сравнение	Цифра	Частичный корень
                -----------------------------------------
    01.10.00.10,					0
    --
    01.			>= 01	да	1	1
    01.
    -----
     0.10		        >= 1.01 нет	0	10
       -----
       10.00		>= 10.01 нет	0	100
       --------
       10.00.10		>= 100.01 да	1	1001
        1.00.01,
      ----------	обратим внимание дошли до запятой -
            можем продолжать и дальше
        1.00.01,00	        >= 1001.01 да	1	1001,1
          10.01,01
      ------------------
           1.11,11.00 	>= 10011.01 да  1	1001,11
           1.00,11.01
           ---------------
             10,11.11.00	>= 100111.01 да  1	1001,111
         10,01.11.01
            итд

Проверим:
        1001
        *   1001
      ------------
        1001
           0000
              0000
             1001
      ------------
         1010001

        1010
        *	1010
      ------------
            0000
               1010
              0000
             1010
           -----------
             1100100

            1100100 больше
            1100010
            1010001 меньше

    так что квадратный корень мы нашли правильно

Соответсвенно квадратный корень в двоичной системе относительно легко вычисляется
(не на много сложнее деления).

  Прочие операции

FABS    |X|			сбрасываем бит знака в ноль
FCHS	-X			инвертируем бит знака
FREM	остаток от деления X/Y	REM(X/Y) = X - X/Y
FRNDINT округление к целому


40.1.2. ВЫЧИСЛЕНИЕ СЛОЖНЫХ ФУНКЦИЙ

THIS SECTION IS UNDER CONSTRUCTION

Основные алгоритмы для вычисления транцедентальных функций:

1) CORDIC
   (Coordinate Rotation Digital Computing)

Идея: поворот осей координат на фиксированный угол меньше A.

    |cos(A)   -sin(A)| |x|   |x'|
    |sin(A)    cos(A)| |y| = |y'|

    x' = x * cos(A) - y * sin(A)
    y' = y * cos(A) + x * sin(A)

    x' / cos(A) = x - y * tg(A)
    y' / cos(A) = y + x * tg(A)

    A		tgA
    45'		1
    26.565'	        1/2
    14.036'		1/4
    7.125'		1/8
    3.576'		1/16
    1.789'		1/32
    0.895'		1/64
    0.4476'		1/128

Делаем сдвиг на такой угол A, чтобы tag(A) = +- 2^(-i)

    x{i+1} = K{i} * (x{i} - (y{i}*d{i}*2^(-i))
    y{i+1} = K{i} * (y{i} + (x{i}*d{i}*2^(-i))
     где,
    d{i} = +- 1  (направление сдвига)
    K{i} = cos(arctg(2^(-i)))

    cos(arctg(2^(-i))) = 1/sqrt(1 + 2^(-2*i))

THIS SECTION IS UNDER CONSTRUCTION

2) Апроксимация
   (convergence Computation method)
   Табличная или по аппроксимирующему полиному
   Затем добиваем ряд как разность, он тоже быстро сходится.

Один из вариантов для ряда: метод Ньютона

    X{n+1} = Xn - F(Xn)/F'(Xn)  в окрестности точки

Сначала берем некое приближенное значение, затем считаем по рекуррентной
формуле.

Примеры:

Надо
вычислить			X{n+1}

SQRT(A)		X^2 - A		0.5 * (Xn + A/Xn)
A^(1/3)		X^3 - A		1/3 * (2Xn + A/(Xn^2))
1/SQRT(A)	X^-2 - A	Xn/2 * (3 - A * Xn^2)
1/A		X^-1 - A	Xn * (2 - A * Xn)

итд

Как узнать где остановится для заданной точности?

X + Y = X*(1+Y/X), если Y/X меньше чем заданная точность, то все приехали.

абсолютная_ошибка    = точное_значение - приближенное_значение
относительная_ошибка = ошибка / точное_значение


40.1.3. РЕАЛЬНЫЕ ОПЕРАЦИИ

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

Есть операция FPTAN которая вычисляет два числа X и Y, такие что
    {X,Y} = FPTAN(z)

    tg(z)  = Y/X
    ctg(z) = X/Y

для вычисления sin и cos:
    {X,Y} = FPTAN(z/2)
    sin(z) = 2 * (Y/X) / [ 1 + (Y/X)^2 ]
    cos(z) = [ 1 - (Y/X)^2 ] / [ 1 + (Y/X)^2 ]
    sec(z) = 1 / sin(z)
    cosec(z) = 1 / cos(z)

также помним, что:
    sin(x) = cos(PI/2 - x)
    tg(z)  = - tg(-z)
    tg(N*PI + x) = tg(x)
    sin(x)^2 + cos(x)^2 = 1
    tg(x) * ctg(x) = 1

Есть операция FPATAN
    {X,Y} = FPATAN(z)

    arctg(z) = Y/X
    arcctg(z) = X/Y
    arcsin(z) = arctg(z/SQRT([1-z]*[1+z]))
    arccos(z) = 2 * arctg(SQRT([1-z]/[1+z]))

F2XM1	(2^X)- 1
FYL2X	Y * log{2}(X)
FYL2XP1	Y * log{2}(X+1)

    log{e}(X)  = log{e}(2)  * log{2}(X)
    log{10}(X) = log{10}(2) * log{2}(X)

    2^X  = ((2^X) - 1) + 1
    e^X  = 1 + (2^(X * log{2}(e)) - 1)
    10^X = 1 + (2^(X * log{2}(10)) - 1)
    X^Y  = 1 + (2^(Y * log{2}(X)) - 1)

Почему именно такие функции:
    2^x - 1
    ln(1+x)

для повышения точности вычислений

Пример реального кода (имеем в виду операнды должны быть в пределах)
FTAN
    FPTAN
    FDIVP	ST(1),ST

FSIN
    FPTAN
    FMUL	ST,ST(0)
    FLD	ST(1)
    FMUL	ST,ST(0)
    FADD
    FSQRT
    FDIVP	ST(1),ST


40.2. ЧИСЛОВАЯ ЛОГАРИФМИЧЕСКАЯ СИСТЕМА

THIS SECTION IS UNDER CONSTRUCTION

NLS  (Numeric Logarithmic System)

Числовая логарифмическая система использует представление чисел с плавающей
точкой в логарифмическом формате.
Число представляется в виде:

    X = +- b^p 	, где b - основание логарифма
                  p = log{b}|x|	(p - число с фиксированной точкой)

пара (знак_числа, логарифм)

Флаги содержат информацию о exceptions.
В общем то они пока не стандартизированны.

-----------------------------------------
s p		значение
-----------------------------------------
1 FF.7FFFFF
1 FF.000000	-1/2
1 FE.000000	-1/4
1 80.000000	-0
1 7F.7FFFFF	-infinity

1 01.00000	-2
1 00.000000	-1
0 00.000000	1               	1*2^0
0 01.000000	2			1*2^1
0 02.000000	4			1*2^2
0 0A.000000	1024			1*2^10

0 7F.7FFFFF	+infinity
0 80.000000	+0
0 FE.000000	+1/4
0 FF.000000	+1/2
-----------------------------------------


40.2.1. ОПЕРАЦИИ В NLS

THIS SECTION IS UNDER CONSTRUCTION

  Умножение

Сводится к сложению знака и логарифма.

    log{p}(X*Y) = log{p}(X) + log{p}(Y)

  Деление

Сводится к сложению знака и вычитанию логарифмов.

    log{p}(X/Y) = log{p}(X) - log{p}(Y)

  Квадратный корень

    log{p}(X^2) = log{P}(X*X)   = log{p}(X) + log{p}(X)
            = 2 * log{p}(X) = log{p}(X) << 1

Соответсвенно:
                 ___
    log{p}(\/ X ) = log{p}(X) / 2 = log{p}(X) >> 1

тоже самое с корнями других степеней:

    log{p}(X^3) = log{p}(X*X*X) = 3 * log{p}(X)
           _3 ___
    log{p}( \/ X ) = log{p}(X) / 3

    log{p}(X^(3/2)) = 3/2 * log{p}(X)

           _3 ___
    log{p}( \/X^2) = log{p}(X) * 2/3

  Сложение/Вычитание

Сложение и вычитание - гораздо более трудные операции:

    log{p}(X+Y) = log{p}(X*(1+Y/X)) = log{p}(X) + log{p}(1+Y/X)
    log{p}(X-Y) = log{p}(X*(1-Y/X)) = log{p}(X) + log{p}(1-Y/X)

    пусть D = - (log{p}(X) - log{p}(Y))
    тогда:

    log(1+Y/X) = log(1 + log^-1{p}(D))
    log(1-Y/X) = log(1 - log^-1{p}(D))

Вычисление антилогарифма операция тяжелая, но может быть хорошо аппроксимирована
через ROM а дальше полиномом 2 порядка по 3 точкам.
(Lewis Interpolation)

Интерполяция Льюиса:

Требуется порядка ROM 3K для Single NLP  (32-бит)
              6K для Double NLP  (64-бит)

  Преобразования из FP

    log{p}(x * 2^z) = log{p}(x) + z

    это уже сложнее - поскольку надо считать log{2}(мантисса)
    24MB таблица для Single.

Chin-Long-Wey approximation via division

    log{2}(1.x1x2..xn) = log{2}(1.x1x2..xm) + log{2}(1.00..00c1c2..cm)

    8KB 	Single
    300MB   Double,	но эту аппроксимацию можно будет еще повторить.

    log{2}(1+.x1x2..xn) = log{2}(1+.q1) + log{2}(1+.0q1) + .. + log{2}(1+.0..0qN)


40.2.2. ПРЕМУЩЕСТВА NLS

Скорость:

Размер:


40.3. LI И SLI СИСТЕМЫ

LI  (Level-Index)
SLI (Symmetric Level index)
Позволяют представлять очень большие или очень малые числа

В LI число представляется в виде:

    X = (s,l,i), где
             s - знак числа - 0 или 1
             l - level - целое число от 0 и больше)
             i - index - вещественное число в интервале [0,1)

Число выражается как:

    X = (-1)^s * F(l,i),  где

    F(l,i)  =  e^i,        если i = 0
        =  e^F(l-1,i), если i > 0

    e - это основание для системы (как правило берут 2 или число 'e')

  SLI

В SLI системе добавляется еще один дополнительный бит r (reciprocal) - 0 или 1
который определяет число так:

    X{SLI}(s,r,l,i) =  X{LI}(s,l,i),   если r = 0
            =  1/X{LI}(s,l,i), если r = 1

таким образом SLI позволяет представлять не только очень большие числа
но и очень малые.

Пример SLI чисел (основание е),
число 32-бит:
    -------------------
    1 бит	sign
    1 бит   reciprocal
    3 бита	level
    27 бит	index
    -------------------

-------------------------------------------------------------
s  r  l     i     represents the value
-------------------------------------------------------------
1  1  7  7FFFFFF  negative infinity
1  0  7  7FFFFFE  - 10^(10^(10^(10^(9.7*10^1656518))))
1  0  7  0000000  - 10^(10^(10^(1.01*10^1656520)))
1  0  6  0000000  - 10^(10^(1.01*10^1656520))
1  0  5  0000000  - 10^(1.01*10^1656520)
1  0  4  0000000  -2.3*10^1656520
1  0  3  7FFFFFF  -7.2*10^1656519
1  0  3  0000000  -3814279.1
1  0  2  7FFFFFF  -3814277.9
1  0  2  0000000  -15.1542622
1  0  1  7FFFFFF  -15.1542619
1  0  1  0000000  -2.71828183 = -e
1  0  0  7FFFFFF  -2.71828180
1  0  0  0000001  -1.0000000075
1  1  0  0000000  -1 (exact)
1  1  0  0000001  -0.9999999925
1  1  0  58B90BF  -0.5000000028
1  1  0  58B90C0  -0.4999999990
1  1  1  0000000  -0.3678794411 = -1/e
1  0  0  0000000  -0 (not used)
0  0  0  0000000  0 (exact)
0  1  1  0000000  0.3678794411 = 1/e
0  1  0  7FFFFFF  0.3678794439
0  1  0  58B90C0  0.4999999990
0  1  0  58B90BF  0.5000000028
0  1  0  0000001  0.9999999925
0  1  0  0000000  1 (exact)
0  0  0  0000001  1.0000000075
0  0  0  58B90BF  1.999999988
0  0  0  58B90C0  2.000000003
0  0  0  7FFFFFF  2.71828180
0  0  1  0000000  2.71828183 = e
0  0  1  3CE9CCA  4.999999948 			note 8 usable digits
0  0  1  3CE9CCB  5.000000008 			and no exact value for 5
0  0  2  0000000  15.1542622 = e^e
0  0  3  0000000  3814279.1 = e^(e^e)
0  0  3  4389695  4.999954139*10^100 		note 5 usable digits
0  0  3  4389696  5.000033872*10^100
1  1  0  0000000  infinity
-------------------------------------------------------------


40.10. ЛОГАРИФМЫ

THIS SECTION IS UNDER CONSTRUCTION

Def
===
    ЛОГАРИФМ числа X по основанию P - это показатель степени в которую
    надо возвести число P чтобы получить число X.

Свойства логарифмов:

для любого a,b,c > 0 и  a <> 1:

    log{a}(bc)  = log{a}(b) + log{a}(c)

    log{a}(b/c) = log{a}(b) - log{a}(c)

    log{a}(b^p) = p * log{a}(b)

           _p __
    log{a}( \/ b) = 1/p * log{a}(b)

                 log{c}(b)
    log{a}(b) = ------------
             log{c}(a)

    a^(log{a}(b)) = b

    ln X = log{e} (x),  где e - число Эйлера
    lg X = log{10}(x)

    10^X = 10^{X} * 10^[X]
        где {X} - дробная часть числа X
            [X] - целая часть числа X

  Таблицы логарифмов

Десятичная:

    --------------
    num	log
    --------------
    1	0.000
    2	0.301
    3	0.477
    4	0.602
    5	0.699
    6	0.778
    7	0.845
    8	0.903
    9	0.954
    10	1.000
    --------------

Двоичная (логарифм по основанию 2)
данные в десятичной системе счисления:

 -------------------------------------------------------------
x   log{2}(x)	x   log{2}(x)	x   log{2}(x)   x   log{2}(x)
 -------------------------------------------------------------
1   0,00000	17  4,08746	33  5,04439	49  5,61471
2   1,00000	18  4,16993	34  5,08746	50  5,64386
3   1,58496	19  4,24793	35  5,12928	51  5,67243
4   2,00000	20  4,32193	36  5,16993	52  5,70044
5   2,32193	21  4,39232	37  5,20945	53  5,72792
6   2,58496	22  4,45943	38  5,24793	54  5,75489
7   2,80735	23  4,52356	39  5,28540	55  5,78136
8   3,00000	24  4,58496	40  5,32193	56  5,80735
9   3,16993	25  4,64386	41  5,35755	57  5,83289
10  3,32193	26  4,70044	42  5,39232	58  5,85798
11  3,45943	27  4,75489	43  5,42626	59  5,88264
12  3,58496	28  4,80735	44  5,45943	60  5,90689
13  3,70044	29  4,85798	45  5,49185	61  5,93074
14  3,80735	30  4,90689	46  5,52356	62  5,95420
15  3,90689	31  4,95420	47  5,55459	63  5,97728
16  4,00000	32  5,00000	48  5,58496	64  6,00000
 -------------------------------------------------------------

  Логарифмическая линейка

3 + 4 = 7

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

2 * 3 = 6


40.11. ФОРМУЛА ТЕЙЛОРА

THIS SECTION IS UNDER CONSTRUCTION

              F'(a)*(x-a)   F''(a) * (x-a)^2	      F(a) * (x-a)^n
F(x) = F(a) + ----------- + ---------------- + ... +  ------------------ + ...
                  1!              2!                          n!

TODO: Частные случаи

e^x      = 1 + x/1!  + x^2/2! + .. + x^N/N! + ...

sin x    = x - x^3/3! + x^5/5! - x^7/7! + .... + (-1)^((n-1)/2) * x^N/N!

cos x    = 1 - x^2/2! + x^4/4! - x^6/6! + ...  + (-1)^(n/2) * x^N/N!

ln(1+x)  = x - x^2/2  + x^3/3  - x^4/4  + ...  + (-1)^(n-1) * x^N/N

(1+x)^a  = 1 + a*x/1! + a(a-1)*x^2/2! +... a(a-1)..(a-n+1)*x^n/n!

arctg x  = x - x^3/3 + x^5/5 - x^7/7 + .... + (-1)^((n-1)/2) * x^N/N


40.12. НЕКОТОРЫЕ СВЕДЕНИЯ ИЗ ТРИГОНОМЕТРИИ

THIS SECTION IS UNDER CONSTRUCTION

  Sin/Cos

sin^2(x) + cos^2(x) = 1

sin(A+B) = sin A cos B + sin B cos A
sin(A-B) = sin A cos B - sin B cos A

cos(A+B) = cos A cos B - sin A sin B
cos(A-B) = cos A cos B + sin A sin B

sin(2X) = 2 sin X cos X

cos(2X) = cos^2(X) - sin^2(X)

  Tan/Cot

  Sec/Csc

  ArcSin/ArcCos

  ArcTan


40.13. BCD12 ЧИСЛА С ПЛАВАЮЩЕЙ ТОЧКОЙ

Иногда в микроконтроллерах используют формат BCD12 для работы:
(Реализован не аппаратно, а программно)

---------------------------------------------------------------------
Name	Description		Bits	BCDs	Range
---------------------------------------------------------------------
S	Sign of number		4	1	0-1 (BCD)
S	sign of exponent	4	1	0-1 (BCD)
E	exponent		16	4	0-9999
M	significand		72	18	0-999999999999999999
---------------------------------------------------------------------

Total size = 96 bit (12 bytes)

Significand is normalized 1.00000...9.99999
encoding for zero 0.00000 is special
if S byte contain FFh it means NaN


41. АРИФМЕТИКА

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

    o Арифметика с фиксированной точкой
    o Арифметика двойной точности
    о Арифметические хаки
        о Реализация функций
        о Умножение на константу
        о Деление на константу


41.1. АРИФМЕТИКА С ФИКСИРОВАННОЙ ТОЧКОЙ

THIS SECTION IS UNDER CONSTRUCTION

  F-формат

Числа с фиксированной точкой F-формата напоминают целые числа, в которых
где то находится точка.

Числа могут быть знаковыми/беззнаковыми. Еще может быть вариант с выделенным знаком.

Например для четырехбитных чисел с фиксировнной точкой.

    Беззнаковый:
        --------------------
        2^1  2^0 . 2^-1 2^-2
        --------------------
        00.00  = 0
        00.01  = 0.25
        00.10  = 0.5
        00.11  = 0.75
        01.00  = 1
        01.01  = 1.25
        ....
        11.11  = 3.75
        --------------------

    Знаковый:
        --------------------
        2^1 2^0  . 2^-1 2^-2
        --------------------
        00.00   = 0
        00.01   = 0.25
        ...
        01.00   = 1
        ...
        01.11   = 1.75
        11.11	= -0.25
        11.10	= -0.5
        11.01	= -0.75
        11.00	= -1
        10.00   = -2
        --------------------

    С выделенным знаком:
        --------------------
        S  2^0   . 2^-1 2^-2
        --------------------
        00.00	= 0
        00.01	= 0.25
        ...
        01.00	= 1
        ..
        01.11	= 1.75
        10.00   = -0
        10.01   = -0.25
        ...
        11.00   = -1
            ...
        11.11   = -1.75
        ---------------------

Арифметика с фиксированной точкой:

Сложение

        XXXX.XX
        +   XXXX.XX
       --------------
            XXXX.XX

        XXXX.XX
        -   XXXX.XX
       --------------
            XXXX.XX

Умножение

        XXXX.XX
        *   XXXX.XX
       --------------
            XXXXXX
          XXXXXX
             XXXXXX
            XXXXXX
           XXXXXX
          XXXXXX
         ---------------
          XXXXXXXX.XXXX

  Q-формат

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

От переполенения при умножении можно избавиться если представлять числа
не более чем единица по модулю тогда:

        A * B < MIN(A,B)
например:
        0.6 * 0.2 = 0.12
        0.9 * 0.9 = 0.81
        0.1 * 0.1 = 0.01

Q-format чисел с фиксированной применяется в основном в DSP
(например в выпускаемых TI)

    -----------------------------------
    -2^0 . 2^-1  2^2  ......    2^(-N+1)	веса разрядов
    -----------------------------------
    -1     0.5   0.25  .....                веса разрядов
    -----------------------------------

Q формат позволяет представлять числа в диапазоне

        -1 <= X < 1

--------------------------------------------------
Тип числа		Q16		Q32
Разрядность бит         16		32
Largest (positive)	1-2^-15		1-2^-31
Smallest (positive)	2^-15		2^-31
Smallest (negative)	-1		-1
---------------------------------------------------

    Самое большое число   имеет вид 0.11..11  = 1-2^-(N-1)
    Самое маленькое число имеет вид 1.00..00  = -1

    Рассмотрим трехбитные числа в Q-формате:

        --------------
        0.00	0
        0.01	0.25
        0.10	0.5
        0.11	0.75
        1.00	-1
        1.01	-0.75
        1.10	-0.5
        1.11	-0.25
        --------------

Сложение/вычитание в Q-формате происходит как с обычными числами.
При этом как правило используют арифметеку с насыщением.

    0.100 + 0.100 =  1 (не представимо) = 0.111 насыщение.

Умножение выполняется как для знаковых чисел (т.е используя расширение знака).

    0.100 * 0.100 = 0.010  все ok

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

    1.000 * 1.000 = 1 (не представимо)

    -1.0 * -1.0 = 1  (а 1.0 - непредставимо в Q-формате)

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

Таким образом алгоритм умножения получается:
    Умножить знаково
    Сдвиг влево на 1 позицию
    Если биты знака равны 01 то сделать насыщение.


41.2. АРИФМЕТИКА С НАСЫШЕНИЕМ

THIS SECTION IS UNDER CONSTRUCTION

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

В отличии от обычного сложения/вычитания в дополнительном коде, когда
и signed и unsigned варианты могут делаться одной командой, для
saturated арифметики - это совершенно разные команды.

Например:

         unsigned
    0000   -   0001   = FFFF

         unsigned
        saturated
    0000   -   0001   = 0000

          signed
        saturated
    0000   -   0001   = FFFF  (-1)

    - Add Saturated Signed
    - Add Saturated Unsigned
    - Subtract Saturated Signed
    - Subtract Saturated Unsinged
    - Multiply Saturated Signed
    - Multiply Saturated Unsigned
    - Divide   Saturated Signed
    - Divide   Saturated Unsigned

Если хочеться сделать насыщения на более ограниченный диапазон чем разрядная сетка
то после Saturated операций делается операции Max и Min с соответсвующими
константами, которые задают диапазон. И конечно Max и Min есть Singed и Unsigned:

    - Signed Maximum
    - Unsigned Maximum
    - Singed Minimum
    - Unsigned Minimum

  Add Saturated Unsigned

Привет кода на C для 16-бит

// Unsigned Saturated Add, sizeof(int) = 2
unsigned int usadd(unsigned int a, unsigned int b)
{
    unsigned int result;
    unsigned int maximum;

    maximum = (a > b)? a : b;
    result  = a + b;

    // Если произошло переполнение, то результат будет
    // меньше чем максимальный операнд

    return (result >= maximum)? result : 0xffff;
}

  Subtract Saturated Unsigned

// Unsigned Saturated Sub, sizeof(int) = any
unsigned int ussub(unsigned int a, unsigned int b)
{
    if (b >= a) return 0;
    return a - b;
}

  Add Saturated Signed

Пример кода на C для 16 бит:

// Saturated Add, sizeof(int) = 2
int	sadd(int a, int b)
{
    int	result;

    result	= a + b;
    if (((a^b) & 0x8000) == 0)
    {
        // same sign
        if ((result^a) & 0x8000)
        {
            // result have different sign, that operand
            result = (a > 0)? 0x8000: 0x7fff;
        }
    }
    return	result;
}

    int	sadd(int x, int y)
    {
        int   sum = x + y;
        int   overflow = (x ^ sum) & (y ^ sum);
        int   big = (x >> 31) ^ INT_MAX;
        return	overflow < 0 ? big : sum;
    }

  Subtract Saturated Signed

  Multiply Saturated Unsigned Low

unsigned int  smul(unsigned int l, unsigned int r)
{
    if (r == 0) return 0;
    if (l > ((-1) / r)) return -1;	// overflow
    return	l * r;
}

  Деление

Деление с насыщением - очень интересная операция:
Мы можем делить на 0.
В этом случае мы должны получить наибольшее число с учетом знака.
Ну и в варианте когда результат больше адрессной сетки - то же
самое.

  Conditional Move и Saturated операции

Если микропроцессор поддерживает команду Conditional Move,
то арифметику с насыщением можно более легко реализовать на более
низком уровне (особенно для unsigned чисел):

  Вычисление MAX/MIN

Макросы для ассемблера x86:

umax	macro	x,y
    cmp	x,y
    cmovc	x,y
    endm

smax	macro	x,y
    cmp	x,y
    cmovl	x,y
    endm

umin	macro	x,y
    cmp	x,y
    cmovnc	x,y
    endm

smin	macro	x,y
    cmp	x,y
    cmovg	x,y
    endm

  Насыщение до указанных границ

urange	macro	x, minrange, maxrange
    umax	x, minrange
    umin	x, maxrange
    endm

srange	macro	x, minrange, maxrange
    smax	x, minrange
    smin	x, maxrange
    endm

  Собственно saturated операции

TODO: не помню - посмотреть есть ли варианты CMOV c imm операндом

addus	macro	x,y
    add	x,y
    cmovc	x, MAX_VALUE
    endm

subus	macro	x,y
    sub	x,y
    cmovc	x,0
    endm

mulus	macro	x,y
    imul	x,y
    cmovc	x, MAX_VALUE
    endm

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


41.3. АРИФМЕТИКА ДВОЙНОЙ И МНОГОКРАТНОЙ ТОЧНОСТИ

  Сложение и Вычитание

Сложение:
    A + B  :  result[high] = A[high] + B[high] + carry_add(A[low],B[low])
          result[low]  = A[low]  + B[low]

Вычитание:
    A + B  :  result[high] = A[high] - B[high] - carry_sub(A[low],B[low])
          result[low]  = A[low]  - B[low]

Для начала посмотрим на Carry Flag и команду Addition with Carry.

    Пусть EBX указывает на первое число
    Пусть ECX указывает на второе число
    Пусть EDX указывает на результат

    mov	eax,[ebx]
    add	eax,[ecx]
    mov	[edx],eax
    mov	eax,[ebx+4]
    adc	eax,[ecx+4]	; Вот зачем надо сложение с CF
    mov	[edx+4],eax

    mov	eax,[ebx]
    sub	eax,[ecx]
    mov	[edx],eax
    mov	eax,[ebx+4]
    sbb	eax,[ecx+4]	; Вот зачем нужно вычитание с CF
    mov	[edx+4],eax

Соответсвенно повторяется нужное число раз, если число большое:

Как мы помним для дополнительного кода сложение/вычитание одинаково для
знаковых и беззнаковых чисел.

  Умножение

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

Беззнакое умножение - берем чисто частные произведения, знак не расширяем

Знаковое умножение - каждое частное произведение знаково расширяется до
максимального размера.

Упрошенные случаи - умножение на число половинного размера
(Количество частных произведений сокращается).

В случае если нам надо число той же разрядности что и опреанды -
имеем multiply low, во-первых одно из частных умножений делать не надо,
соответсвенно на единицу уменьшается число чаcтных сумм,
во вторых эта операция одинакова и для знаковых и для беззнаковых чисел.

Еще раз проиллюстируем важность оптимизации при умножение на числа младшего размера.

    --------------------------------------
    Operand	Operand	Result	MULS	ADDS
    --------------------------------------
    4	4	8	16	15
    4	2	8	8	7
    4	1	8	4	3
    --------------------------------------

Поэтому надо пользоваться каждым случаем для минимизации размера операндов для
умножения.

  Умножение Карацубы

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

Пусть нам надо перемножить (A1,A0) на (B1,B0)

В обычном случае умножения столбиком:

    A*B = (A1*B1) * 2^2n  +
          (A0*B1) * 2^n   +
          (A1*B0) * 2^n   +
          (A0*B0)

имеем 4 умножения.

Идея лежащая в основе метода:
Хочеться получить A0*B1 + A1*B0 сразу, как это можно сделать:

Рассмотрим произведение:
    (A0 + A1) * (B0 + B1) =

    A0 * B0 + A0 * B1 + A1 * B0 + A1 * B1
                  =======   =======

подчеркнуты части которые нам нужны.

Соответсвенно
    A0 * B1 + A1 * B0 = (A0 + A1)*(B0 + B1) - A0*B0 - A1*B1.

Но фишка в том, что в процессе умножения мы так и так вычисляем
A0 * B0  и  A1 * B1.

Рассчитаем:
    X = A0 * B0
    Y = (A0 + A1) * (B0 + B1)
    Z = X1 * Y1

Собственно результат будет:

    Z * 2^2n + (Y - Z -A)*2^n + X

На самом деле есть ньюансы:

  Получение Carry

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

Если делать реализацию на чистом ЯВУ - то во первых надо посмотреть какая
архитектура у платформы - совершаются ли операции точно того размера как мы хотим,
или они совершаются с sign-extended в больший размер.
Но в любом случае  при реализации на ЯВУ приходиться прибегать к ухищрениям.

(1) Использовать блоки более короткого размера чем длинна слова и всегда
    zero-extend операнды.
    При сложении вычитании смотреть выходим ли мы за пределы диапазона.

    unsigned short s1;    	// source chunk 1
    unsigned short s2;		// source chunk 2
    unsigned short result;	// resulted chunk

    unsigned long r1 = s1;
    unsigned long r2 = s2;

    unsigned long t = r1 + r2;
    result = (unsigned short) t;
    carry  = (t > 0x10000)? 1 : 0;	// если вылезло за пределы то был перенос/заем

(2) Вычислять Carry из соотношений

                          U _
    carry(X + Y) = X  > Y

Посмотрим на примере 2 битовых чисел
                                _
    X	Y	X+Y	Y	C
    00	00	0.00	11	0
    00	01	0.01	10      0
    00	10	0.10	01      0
    00	11	0.11	00      0
    01	00	0.01	11      0
    01	01	0.10	10      0
    01	10	0.11	01      0
    01	11	1.00	00      1
    10	00	0.10	11      0
    10	01	0.11	10      0
    10	10	1.00	01      1
    10	11	1.01    00      1
    11	00	0.11    11      0
    11	01	1.00    10      1
    11	10	1.01    01      1
    11	11	1.10    00      1

Попробуем написать формулу для carry(X - Y)
она вообще очень проста и естественна

                          U
     carry(X - Y) = X < Y

                                                _             U   _
    carry(X + Y) = carry(X - (-Y)) = carry(X - (Y + 1)) =  X  <  (Y + 1)

  Умножение чисел со знаком

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

    ---------------------
    A	B	A*B
    ---------------------
    +	+	+
    +	-	-
    -	+	-
    -	-	+
    ---------------------

Собсвенно sign(A*B) = sign(A) xor sign(B)

  Деление чисел со знаком

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

    -------------------------------
    A	B	A/B	A%B
    -------------------------------
     7	 5	 1	 2
     7	-5	-1	 2
    -7	 5	-1	-2
    -7	-5	 1	-2
    -------------------------------

Таким образом знак частного (quotient) положительный если знаки делимого (dividend)
и делителя (divisor) совпадают, и отрицательный в других случаях.

    sing(quotient) = sign(dividend) xor sign(divisor)

А знак остатка (remainder) совпадает со знаком делимого (dividend).

    sign(remainder) = sign(dividend)

  Сравнения

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

    A == B :  if (A[high] == B[high])
          {
            if (A[low] == B[low]) then true
          }
          false

    A != B :  if (A[high] != B[high]) then true
          if (A[low]  != B[low])  then true
          false

    A > B  :  if (A[high] > B[high]) then true
          if (A[high] == B[high])
          {
            if (A[low] > B[low]) then true
          }
          false

    A >= B  : if (A[high] > B[high]) then true
          if (A[high] == B[high])
          {
            if (A[low] >= B[low]) then true
          }
          false

  Побитовые логические операции

Побитовые логические операции выполняются над каждой из частей отдельно

    A & B  :  result[high] = A[high] & B[high]
          result[low]  = A[low]  & B[low]

    A | B  :  result[high] = A[high] | B[high]
          result[low]  = A[low]  | B[low]

    A ^ B  :  result[high] = A[high] ^ B[high]
          result[low]  = A[low]  ^ B[low]

    ~A     :  result[high] = ~A[high]
          result[low]  = ~A[low]

Кстати имейте в виду что операцию NEG то есть -X, для чисел многократной точности
удобнее минимизировать через -X =  ~A + 1,  это быстрее чем как  0-X
так как для операции +1, можно прооптимизировать время выполнения следя за
carry flag в процессе. Если он неустановлен для какой то частной суммы, то для всех
старший частных сумм - операцию можно уже не делать.

  Псевдовекторные операции

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

Сложение:

Смысл техники - мы маскируем старший бит у элемента вектора и складываем
                такие части - они никак не вылезут за пределы вектора.
         Затем сверху накладываем сумму для старшего бита, поскольку
        нас не интересует carry, то мы просто делаем xor

Addition:

    t    = (x & 0x7f7f7f7f) + (y & 0x7f7f7f7f)
    sum  = ((x xor y) & 0x80808080) xor t)

Subtraction:
    t    = (x & 0x7f7f7f7f) - (y & 0x7f7f7f7f)
    sum  = ((x xor y) | 0x7f7f7f7f) eqv t

Multiply Low:

Negate:

Shift Left:

Constant to Vector:

Constant to Vector:

Compare patrial unsigned:

Compare partial signed:

Сложности псевдовекторных операций
(представленны для векторов длинны 4):

    -------------------------------------------
    Сложение		1	сложение
                5	логических
    -------------------------------------------
    Умножение на скаляр     2	умножения
                5	логических
    -------------------------------------------
    Сдвиг			1	сдвиг
                1	логическая
    -------------------------------------------
    Negate (-X)		1	вычитание
                3	логических
    -------------------------------------------
    Логические              1	логическая
    -------------------------------------------
    Сравнение (беззнаковое)	1	сравнение
                2	логических
    -------------------------------------------
    Сравнение (знаковое)	1	сравнение
                    (2	сдвига)
                2	логических
    -------------------------------------------


41.4. СООТНОШЕНИЯ В ДОПОЛНИТЕЛЬНОМ КОДЕ

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

    -X = NOT(X) + 1
    -X = NOT(X - 1)

    NOT(X) = -X - 1
    - NOT(X) = X + 1
    NOT(-X) = X - 1

    X + Y = X - NOT(Y) - 1
          =	(X ^ Y) + 2 (X & Y)
          = (X | Y) + (X & Y)
          = 2 (X | Y) - (X ^ Y)

    X - Y = X + NOT(Y) + 1
          = (X ^ Y) - 2(NOT(X) & Y)
          = (X & NOT(Y)) - (NOT(X) & Y)
          = 2 (X & NOT(Y)) - (X ^ Y)

    X ^ Y = (X | Y) - (X & Y)

    X & NOT(Y) = (X | Y) - Y
           = X - (X & Y)

    NOT(X - y) = Y - X - 1 = NOT(X) + Y

    X EQV Y  = (X & Y) - (X | Y) - 1
         = (X & Y) + NOT(X | Y)

    X | Y = (X & NOT(Y)) + Y
    X & Y = (NOT(X) | Y) - NOT(X)


41.5. РЕАЛИЗАЦИЯ СПЕЦИАЛЬНЫХ ФУНКЦИЙ

THIS SECTION IS UNDER CONSTRUCTION

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

С другой стороны если их нет, то решения в лоб оказываются слишком медленными.

В этой секции расказывается как их проэмулировать если они недоступны
(например не реализованны аппаратно, или ваш язык программирования не поддерживает
такие операции).

Поскольку у нас все укладывается в логические функции, то даже условное присваивание:

    if (a < b)
    {
        x = c;
    } else {
        x = d;
    }

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

    x = (((a - b) >>> (sizeof(int) * CHAR_BITS - 1)) & (c ^ d)) ^ d;

  Shift Arithmetic Right

Арифметический сдвиг вправо

для 32-битной машины в дополнительном коде:

    X >>> N = ((X + 0x80000000) >> N) - (0x80000000 >> N)

  Generalized Shift

Реализация функции Generalized Shift для 32-битных архитектур в доболнительном коде:
Generalized shift - функция которая может сдвигать и влева и вправо (в зависимости от
знака аргумента, а так же может сдвигать на большее число бит чем размер операнда,
естественно в этом случае результат будет 0.

unsigned long genshift(unsigned long v, int x)
{
    int	a,b;
    a = (v << x) & -(((unsigned int) x) < 32);
    x = -x;
    b = (v >> x) & -(((unsigned int) x) < 32);
    return	a | b;
}

  ABS/NABS

ABS - абсолютная величина (модуль числа)

    ABS(X) = |  X,  X >= 0
         | -X,  X <  0

NABS - негативная абсолютная величина числа

    NABS(X) = |  X,  X <= 0
          | -X,  X >  0

    -------------------------------------
    Ops	MSB	Result	 Result_MSB
    -------------------------------------
    ABS	0	X	0
    ABS	1	-X	0
    NABS	0	-X	1
    NABS	1	X	1
    -------------------------------------

для 32-битной машины в дополнительном коде:

    пусть	Y =  X >>> 31,  тогда
                   (31 = sizeof(int) * CHAR_BITS - 1)

    ABS(X)  = (X ^ Y) - Y  = (X + Y) ^ Y  = X - (2X & Y)

    NABS(X) = Y - (X ^ Y)  = (Y - X) ^ Y  = (2X & Y) - X

  Rotate

Rotate Left:

    X <-< N = (X << N) | (X >> (32 - N))

Rotate Right:

    X >-> N = (X >> N) | (X << (32 - N))

  Sign

    Sign(X) = | -1, X < 0
          |  0, X = 0
          |  1, X > 0

для 32-битной машины в дополнительном коде:

    Sign(x) = (X >>> 31) | (-X >> 31)

    Sign(X) = (X > 0) - (X < 0)

  Population count

Population count - возвращает число единичных бит в аргументе
Очень полезная вещь для медийных приложений.
Аппаратная реализация - каскад сумматоров:

Вариант в лоб:

    for (c = 0; v; c++)
    {
        v &= v - 1; // clear the least significant bit set
    }

для 32-битной машины в дополнительном коде:

    int	pop(unsigned x)
    {
        x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
        x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
        x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f);
        x = (x & 0x00ff00ff) + ((x >> 8) & 0x00ff00ff);
        x = (x & 0x0000ffff) + ((x >> 16) & 0x0000ffff);
        return x;
    }

B[0] = 0x55555555 = 01010101 01010101 01010101 01010101
B[1] = 0x33333333 = 00110011 00110011 00110011 00110011
B[2] = 0x0F0F0F0F = 00001111 00001111 00001111 00001111
B[3] = 0x00FF00FF = 00000000 11111111 00000000 11111111
B[4] = 0x0000FFFF = 00000000 00000000 11111111 11111111

    pop(x) = x - SUM{1,31}(X >> 1)

Интересно посмотреть на график функции Population Count:

Реализция Population count используя таблицу:

static const unsigned char BitsSetTable256[256] =
{
#   define B2(n) n,     n+1,     n+1,     n+2
#   define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#   define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
    B6(0), B6(1), B6(1), B6(2)
};

c = BitsSetTable256[v & 0xff] +
    BitsSetTable256[(v >> 8) & 0xff] +
    BitsSetTable256[(v >> 16) & 0xff] +
    BitsSetTable256[v >> 24];

  Дистанция Хэмминга

    dist(X,Y) = pop(X ^ Y)

  Четность

    parity(X) = XOR{i=0,N-1}(X >> i)

Тупо в лоб:

    bool parity = false;  // parity will be the parity of v

    while (v)
    {
        parity = !parity;
        v = v & (v - 1);
    }

для 32 разрядной машины:

    y = x ^ (x >> 1)
    y = y ^ (y >> 2)
    y = y ^ (y >> 4)
    y = y ^ (y >> 8)
    y = y ^ (y >> 16)

    v ^= v >> 16;
    v ^= v >> 8;
    v ^= v >> 4;
    v &= 0xf;
    return (0x6996 >> v) & 1;

Вариант через таблицу:

static const bool ParityTable256[256] =
{
#   define P2(n) n, n^1, n^1, n
#   define P4(n) P2(n), P2(n^1), P2(n^1), P2(n)
#   define P6(n) P4(n), P4(n^1), P4(n^1), P4(n)
    P6(0), P6(1), P6(1), P6(0)
};

// for 32-bit words:
v ^= v >> 16;
v ^= v >> 8;
bool parity = ParityTable256[v & 0xff];

  Average

Unsigned

  Average Round to zero

                     X+Y                          U
    ROUNDTOZERO(-----) = (X & Y) + ((X xor Y) >> 1)
                  2

  Average Round toward zero

             X+Y                          U
    ROUNDTOWARDZERO(-----) = (X | Y) - ((X xor Y) >> 1)
                      2

  Minimum/Maximum

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

    MIN(X,Y) = Y ^ ((X ^ Y) & - (X < Y))

    MAX(X,Y) = X ^ ((X ^ Y) & - (X < Y))

  Number of Leading Zero

THIS SECTION IS UNDER CONSTRUCTION

    nlz(x)

    unsigned int nlz(register unsigned int x)
    {
            x |= (x >> 1);
            x |= (x >> 2);
            x |= (x >> 4);
            x |= (x >> 8);
            x |= (x >> 16);
            return(32 - ones(x));
    }

Есть также аналог - number of Leading Ones.

  Number of Trailing Zero

THIS SECTION IS UNDER CONSTRUCTION

    ntz(x)

    int ntz(unsigned x)
    {
        unsigned y, bz, b4, b3, b2, b1, b0;
        y = x & -x; // Isolate rightmost 1-bit.

        bz = y ? 0 : 1; // 1 if y = 0.
        b4 = (y & 0x0000FFFF) ? 0 : 16;
        b3 = (y & 0x00FF00FF) ? 0 : 8;
        b2 = (y & 0x0F0F0F0F) ? 0 : 4;
        b1 = (y & 0x33333333) ? 0 : 2;
        b0 = (y & 0x55555555) ? 0 : 1;
        return bz + b4 + b3 + b2 + b1 + b0;
    }

    int ntz(unsigned x)
    {
        static char table[32] =
            { 0, 1, 2,24, 3,19, 6,25, 22, 4,20,10,16, 7,12,26,
              31,23,18, 5,21, 9,15,11, 30,17, 8,14,29,13,28,27 };

        if (x == 0) return 32;
        x = (x & -x) * 0x04D7651F;
        return table[x >> 27];
    }

Есть аналог - number of trailing ones.

  Bit Reverse

Меняем порядок битов:

static const unsigned char BitReverseTable256[256] =
{
#   define R2(n)     n,     n + 2*64,     n + 1*64,     n + 3*64
#   define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16)
#   define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 )
    R6(0), R6(2), R6(1), R6(3)
};

// Option 1:
c = (BitReverseTable256[v & 0xff] << 24) |
    (BitReverseTable256[(v >> 8) & 0xff] << 16) |
    (BitReverseTable256[(v >> 16) & 0xff] << 8) |
    (BitReverseTable256[(v >> 24) & 0xff]);

  log{2}

Тупо в лоб:

    while (v >>= 1)
    {
          r++;
    }

Через таблицу:

static const char LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
    -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
    LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};

register unsigned int t, tt; // temporaries

if (tt = v >> 16)
{
  r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else
{
  r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}

  Round to next power of 2

    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;

  Clear all except MSB which is 1

    int  n = v;
    while(v)
    {
        n = v;
        v &= n - 1;
    }

    unsigned int msb32(register unsigned int x)
    {
            x |= (x >> 1);
            x |= (x >> 2);
            x |= (x >> 4);
            x |= (x >> 8);
            x |= (x >> 16);
            return(x & ~(x >> 1));
    }

  Clear all except LSB which is 1

    (x & -x) = (x & ((~x) + 1))

  Bit interleave

unsigned short x;   // Interleave bits of x and y, so that all of the
unsigned short y;   // bits of x are in the even positions and y in the odd;
unsigned int z = 0; // z gets the resulting Morton Number.

for (int i = 0; i < sizeof(x) * CHAR_BIT; i++) // unroll for more speed...
{
  z |= (x & 1U << i) << i | (y & 1U << i) << (i + 1);
}

static const unsigned short MortonTable256[256] =
{
  0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
  0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
  0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
  0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
  0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
  0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
  0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
  0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
  0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
  0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
  0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
  0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
  0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
  0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
  0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
  0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
  0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
  0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
  0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
  0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
  0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
  0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
  0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
  0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
  0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
  0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
  0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
  0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
  0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
  0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
  0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
  0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
};

unsigned short x; // Interleave bits of x and y, so that all of the
unsigned short y; // bits of x are in the even positions and y in the odd;
unsigned int z;   // z gets the resulting 32-bit Morton Number.

z = MortonTable256[y >> 8]   << 17 |
    MortonTable256[x >> 8]   << 16 |
    MortonTable256[y & 0xFF] <<  1 |
    MortonTable256[x & 0xFF];

static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF};
static const unsigned int S[] = {1, 2, 4, 8};

unsigned int x; // Interleave lower 16 bits of x and y, so the bits of x
unsigned int y; // are in the even positions and bits from y in the odd;
unsigned int z; // z gets the resulting 32-bit Morton Number.

x = (x | (x << S[3])) & B[3];
x = (x | (x << S[2])) & B[2];
x = (x | (x << S[1])) & B[1];
x = (x | (x << S[0])) & B[0];

y = (y | (y << S[3])) & B[3];
y = (y | (y << S[2])) & B[2];
y = (y | (y << S[1])) & B[1];
y = (y | (y << S[0])) & B[0];

z = x | (y << 1);


41.6 УМНОЖЕНИЕ НА КОНСТАНТУ

THIS SECTION IS UNDER CONSTRUCTION

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

Умножение на степень двойки:

    X * 2^N 	= (X << N)
    X * (2^N+1)     = (X << N) + X
    X * (2^N-1)	= (X << N) - X

Умножение на константу:

    ---------------------------------------------------------
    операция					операций
    ---------------------------------------------------------
    X * 2  = (X << 1)                       	1
    X * 3  = (X << 1) + X                   	2
    X * 4  = (X << 2)                       	1
    X * 5  = (X << 2) + X                   	2
    X * 6  = (X << 2) + (X << 1)             	3
    X * 7  = (X << 3) - X				2
    X * 8  = (X << 3)				1
    X * 9  = (X << 3) + X				2
    X * 10 = (X * 5) << 1 = ((X << 2) + X) << 1     3
    X * 11 = (X << 4) - (X << 2) - X		4
    X * 12 = (X << 4) - (X << 2) 			3
    X * 13 = (X << 4) - (X << 1) - X		4
    X * 14 = (X << 4) - (X << 1)                    3
    X * 15 = (X << 4) - X                           2
    X * 16 = (X << 4)                               1
    ---------------------------------------------------------

    2	2
    3	2 + 1
    4	4
    5	4 + 1
    6	2 * 3
    7	8 - 1
    8	8
    9	8 + 1
    10	2 * 5
    13	3 * 4 + 1
    15	3 * 5

    итд.

Особенно это эффективно если в микропроцессоре есть совмещенная иниструкция
SHIFT-ADD:

Например:
    HPPA:	SH1ADD, SH2ADD, SH3ADD
    Alpha:  S4ADDL, S8ADDL

000:
     xor    eax,eax
001:
002:
     add    eax,eax
003:
     lea    eax,[eax+eax*2]
004:
     shl    eax,02H
005:
     lea    eax,[eax+eax*4]
006:
     add    eax,eax
     lea    eax,[eax+eax*2]
007:
     lea    ebx,[eax+eax*2]
     lea    eax,[eax+ebx*2]
008:
     shl    eax,03H
009:
     lea    eax,[eax+eax*8]
010:
     add    eax,eax
     lea    eax,[eax+eax*4]
011:
     lea    ebx,[eax+eax*2]
     lea    eax,[ebx+eax*8]
012:
     shl    eax,02H
     lea    eax,[eax+eax*2]
013:
     lea    ebx,[eax+eax*2]
     lea    eax,[eax+ebx*4]
014:
     add    eax,eax
     lea    ebx,[eax+eax*2]
     lea    eax,[eax+ebx*2]
015:
     lea    eax,[eax+eax*2]
     lea    eax,[eax+eax*4]
016:
     shl    eax,04H
017:
     lea    ebx,[eax+eax*8]
     lea    eax,[ebx+eax*8]
018:
     add    eax,eax
     lea    eax,[eax+eax*8]
019:
     lea    ebx,[eax+eax*8]
     lea    eax,[eax+ebx*2]
020:
     shl    eax,02H
     lea    eax,[eax+eax*4]
021:
     lea    ebx,[eax+eax*4]
     lea    eax,[eax+ebx*4]
022:
     add    eax,eax
     lea    ebx,[eax+eax*2]
     lea    eax,[ebx+eax*8]
023:
     lea    ebx,[eax+eax*8]
     shl    eax,05H
     sub    eax,ebx
024:
     shl    eax,03H
     lea    eax,[eax+eax*2]
025:
     lea    eax,[eax+eax*4]
     lea    eax,[eax+eax*4]
026:
     add    eax,eax
     lea    ebx,[eax+eax*2]
     lea    eax,[eax+ebx*4]
027:
     lea    eax,[eax+eax*2]
     lea    eax,[eax+eax*8]
028:
     lea    ebx,[eax+eax*2]
     add    eax,ebx
     lea    eax,[eax+ebx*8]
029:
     lea    ebx,[eax+eax*2]
     shl    eax,05H
     sub    eax,ebx
030:
     add    eax,eax
     lea    eax,[eax+eax*2]
     lea    eax,[eax+eax*4]
031:
     mov    ebx,eax
     shl    eax,05H
     sub    eax,ebx
032:
     shl    eax,05H
033:
     lea    ebx,+0H[eax*4]
     lea    eax,[eax+ebx*8]
034:
     mov    ebx,eax
     shl    eax,05H
     lea    eax,[eax+ebx*2]
035:
     lea    ebx,[eax+eax*2]
     add    eax,ebx
     lea    eax,[ebx+eax*8]
036:
     shl    eax,02H
     lea    eax,[eax+eax*8]
037:
     lea    ebx,[eax+eax*8]
     lea    eax,[eax+ebx*4]
038:
     add    eax,eax
     lea    ebx,[eax+eax*8]
     lea    eax,[eax+ebx*2]
039:
     lea    eax,[eax+eax*2]
     lea    ebx,[eax+eax*2]
     lea    eax,[eax+ebx*4]
040:
     shl    eax,03H
     lea    eax,[eax+eax*4]
041:
     lea    ebx,[eax+eax*4]
     lea    eax,[eax+ebx*8]
042:
     add    eax,eax
     lea    ebx,[eax+eax*4]
     lea    eax,[eax+ebx*4]

043:
     lea    ebx,[eax+eax*2]
     lea    eax,[eax+eax*4]
     lea    eax,[ebx+eax*8]
044:
     shl    eax,02H
     lea    ebx,[eax+eax*2]
     lea    eax,[ebx+eax*8]
045:
     lea    eax,[eax+eax*4]
     lea    eax,[eax+eax*8]
046:
     lea    ebx,[eax+eax*4]
     add    eax,ebx
     lea    eax,[eax+ebx*8]
047:
     lea    ebx,[eax+eax*2]
     lea    eax,[ebx+eax*8]
     lea    eax,[ebx+eax*4]
048:
     shl    eax,04H
     lea    eax,[eax+eax*2]
049:
     lea    ebx,[eax+eax*2]
     add    ebx,ebx
     lea    eax,[eax+ebx*8]
050:
     add    eax,eax
     lea    eax,[eax+eax*4]
     lea    eax,[eax+eax*4]


41.7 ДЕЛЕНИЕ НА КОНСТАНТУ

THIS SECTION IS UNDER CONSTRUCTION

Деление на степень 2:

    X / 2^N     = (X >>> N)		для знаковых и беззнаковых

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

идея:
    X / Y  = X * 1/Y

    Reciprocal = 1/Y
    ----------------------------------------------
    Y	1/Y (decimal)		1/Y (binary)
    ----------------------------------------------
    1	1.0			1.0
    2	0.5			0.1
    3	0.(3)			0.(01)
    4	0.25			0.01
    5	0.2			0.(0011)
    6	0.1(6)			0.0(01)
    7	0.0142857(142857)	0.(001)
    8	0.125			0.001
    9	0.(1)			0.(000111)
    10	0.1			0.0(0011)
    -----------------------------------------------

    -----------------------------------------------
    1/3	0.(0101)
    1/5	0.(0011)
    4/6	0.(1010)
    4/7	0.(1001 0010 0100)
    8/9	0.(1110 0011 1000)
    8/10	0.(1100)
    8/11	0.(1011 1010 0010 1110 1000)
    8/12	0.(1010)
    8/13	0.(1001 1101 1000)
    1/2	0.1
    1/4	0.01
    1/8	0.001
    -----------------------------------------------

    Чтобы 1/Y уместилась в регистр мы умножаем ее на 2^N
    используем умножение N*N в 2N и берем старшую часть.

       Пример:
        45h / 10  размер операции байт

        1/10 = 0.0(0011) в размере байта: 0.00011001

        1/10 * 2^8 ~= 00011001 = 19h

        +-----------+
        | 0100 0101 | 45h
          *	+-----------+
               | 0001 1001 | 19h
  ==============================
    | 0000 0110 | 1101 1011 | 6DBh
    +-----------+-----------+
    +-----------+
             |
             +------> наш результат:  6h  все правильно

    Пример:
        45h / 3   размер операции байт.

        45h = 69 = &b01000101

        1/3 = 0.(01) в размере байта:  0.01010101
        1/3 * 2^8 ~= 01010101 = 55h

        +-----------+
        | 0100 0101 | 45h
          *	+-----------+
               | 0101 0101 | 55h
  ==============================
    | 0001 0110 | 1110 1001 | 16E9h
    +-----------+-----------+
    +-----------+
             |
             +------> наш результат:  16h

    проверка:
        16h * 3 = 42h (потому что не уложились)
                  вообще 3,5,7 - специальные случаи

    почему они специальные случаи:
    возьмем части которые у нас не уместились в байт:

    3	  X *  0.(5) = 0.(5) X как минимум
          чтобы это скоректировать мы можем добавить к X 2
          (при Х близких к FF неудобно).

        +-----------+
        | 0100 0111 | 47h
          *	+-----------+
               | 0101 0101 | 55h
  ==============================
    | 0001 0111 | 1001 0011 | 1793h
    +-----------+-----------+
    +-----------+
             |
             +------> наш результат:  17h

        17h * 3 = 45h	все нормально

    другой вариант:

           2^8 + 2     X
    Q = floor( -------- * --- )
                  3       2^8

    (2^8 + 2) / 3 = 56h

        +-----------+
        | 0100 0111 | 45h
          *	+-----------+
               | 0101 0101 | 56h
  ==============================
    | 0001 0111 | 0010 1110 | 172Eh
    +-----------+-----------+
    +-----------+
             |
             +------> наш результат:  17h

    5	  X * 0.3(3)

                 2^9 + 3     X
    Q = floor ( --------- * --- )
            5       2^9

    7	  X * 0.92..

                          2^10 + 5          X
    Q = floor ( ( floor(( --------- - 2^8)*---) + X) / 4 )
                             7             2^8

  Вычисление остатка

собственно для 2^t

a % b = a % (2^t) = a & (2^t - 1)

Конечно есть специальные варианты для
    2^t - 1
    2^t + 1

TODO: привести примеры

действует для чисел вида k * 2^t

a % b = a % (k * 2^t) = a - ((2^N / k * a / 2^N) & -2^t) * k


41.8. FP ХАКИ

Естественно существуют и FP Hacks, когда вычисления делают приближенно
через integer типы. (Естественно это либо через память, либо если FP регистры позволяют
делать integer операции над ними.

  Быстрая конвертация в Integer

int  FastFloatToInt(float f)
{
    f += (float)(3 << 21);
    return (*((int*) &f) - 0x4ac00000) >> 1;
}

  Быстрый квадратный корень

Ошибка при вычислении не превышает 5%

float FastSqrt(float f)
{
    int t = *(int*) &f;
    t -= 0x3f800000;
    t >>= 1;
    t += 0x3f800000;
    return *(float*)&t;
}

  Быстрый обратный квадратный корень

Если x > 0.25, то ошибка меньше 0.6%

float  FastInvSqrt(float x)
{
    int tmp = ((0x3f800000 << 1) +
           0x3f800000 - *(long*)&x) >> 1;
    float y = *(float *)&tmp;
    return y * (1.47f - 0.47f * x * y * y);
}


50. АРХИТЕКТУРА МИКРОПРОЦЕССОРОВ

Вот мы и переходим от функционально-логического к архитектурному уровню.

!! Главная цель архитектуры: повышение быстодействия (производительности).

    Производительность = объем работы / время

Закон Гроша (Grosch):
    Производителтность прямо пропорциональна квадрату стоимости ЭВМ.
    P = a * c^2

Основные методы повышения быстродействия:

    o  Совершенствование элементной базы
        o Уменьшение размера вентиля
        o Применение материалов с лучшеми характеристиками
        o Коренное изменение технологии (оптическая или 3D)
    o Совершенствование логической структуры (архитектура)
        o Конвееризация
        o Суперскалярность
        o Векторность
        o Сверхоперативная память (cache)
        o Prefetching
        o Предсказание переходов
        o Внеочередное выполнение (out-of-order execution)
        o Мультипроцессорность

Закон Мура:


50.1. ФОН НЕЙМАНОВСКАЯ И ГАРВАРДСКАЯ АРХИТЕКТУРА

Компьютер состоит из 3х основных подсистем: процессор, память и подсистема
ввода-вывода:

        Архитектура
        /          \
    фон Неймановская   Гарвардская

В фон Неймановской архитектуре программы и данные хранятся в общей памяти
(общее адресное пространство) [PC именно такие]

В Гарвардской архитектуре программы и данные хранятся в разных памятях
с независимым доступом (быстрее чем Фон Неймановская, но больше вентилей)


50.2. ПОСЛЕДОВАТЕЛЬНАЯ, ПАРАЛЛЕЛЬНАЯ И КОНВЕЕРНАЯ АРХИТЕКТУРА

Типы паралелизма:

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

Последовательная (Serial) архитектура - пока полностью не выполнена текущая
команда никакие другие не выполняются.

Используется: старые CISC процессоры (микропрограммы).
Недостатки:
    Долгое выполнение  (команда R-R: 8 тактов на 4004).

Производительность:  S (serial) по определению.

  Конвеер

Конвеерная (Pipeline) архитектура - команды выполняются постадийно,
каждая стадия обособлена от другой.

Типичный набор стадий:
    PF	- Prefetch instruction (Выборка инструкции из памяти)
    DC	- Decoding (декодирование)
    EX	- Execute  (выполнение)
    WB	- Write Back (запись результата).

В идеальном случае имеем Perfomance = n*S, где n-число ступеней конвеера.

К сожалению не все так гладко  в жизни, т.к. существует много зависимостей.

Зависимость по данным:

    Команда 3 использует результат команды 2. => команда 3 не может быть
выполнена пока команда 2 не пройдет WB. Конвеер останавливается на 1 такт
(pipeline stalled)

Зависимость по ресурсам:

    Команда 2 использует аппаратный умножитель - время выполнения
умножения 4 такта. Все это время более позние команды ждут пока не смогут
запуститься. Конвеер останавливается на m-1 такт, где m-время выполнения
команды.

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

Зависимость по управлению:

    Пусть команда 2 это условный переход и она нас переносит в
другое место. Мы должны после ee WB начать выбирать конвеер с нового
адресса.  Время задержки = n-2, где n-количество ступеней конвеера

  Параллельная

    Паралельная (Parallel) архитектура - когда команды выполняются
паралельно.

В идеальном случае  Perfomance = m * S, где m-число паралельных устройств

  VLIW

    VLIW (Very Large Instruction Word). Куча команд выполняемых
паралельно заносится в один большой bindle. Внутри bindla нет зависимостей

  Суперконвеерный

    Увеличено число степеней конвеера (обычно более 10). Соответственно
очень жестокие penalty за непредсказанные переходы.


50.2.1. ПРИМЕРЫ КОНВЕЕРОВ РЕАЛЬНЫХ ПРОЦЕССОРОВ

THIS SECTION IS UNDER CONSTRUCTION

  486

 -----------------------------------------------------------------------
PF	Prefetch	выборка команды в один из 2х 16-байтовых буферов
D1	Decode 1	декодирование команды
            (инструкции с префиксом +1 такт)
D2	Decode 2	Вычисление адрессов операндов
            (если индексы то +1 такт)
EX	Execution	Выполнение
WB	Write Back	Запись результатов
 -----------------------------------------------------------------------

  Pentium

 -----------------------------------------------------------------------
PF	Prefetch	выборка команды в один из 4х 32-байтовых буферов
            (2 для sequental prefetch, 2 для predicted-taken jump)
D1	Decode 1	декодирование команды
D2	Decode 2	Вычисление адрессов операндов
EX	Execution	Выполнение
WB	Write Back	Запись результатов
 -----------------------------------------------------------------------
X1	Execute 1	FP Преобразование числа во внутренний 80-бит формат
X2	Execute	2	FP Выполнение
WF	Write Float	FP Округление и запись результата
ER	Error Reporting FP обновление регистра статуса (информирование
            об ошибках).
 -----------------------------------------------------------------------

  Pentium w/MMX

 -----------------------------------------------------------------------
PF	Prefetch	выборка команды в один из 4х 32-байтовых буферов
            (2 для sequental prefetch, 2 для predicted-taken jump)
D1	Decode 1	декодирование команды
D2	Decode 2	Вычисление адрессов операндов
EX	Execution	Выполнение
WB	Write Back	Запись результатов
 -----------------------------------------------------------------------
X1	Execute 1	FP Преобразование числа во внутренний 80-бит формат
X2	Execute	2	FP Выполнение
WF	Write Float	FP Округление и запись результата
ER	Error Reporting FP обновление регистра статуса (информирование
            об ошибках).
 -----------------------------------------------------------------------
MEX	MMX Execute	Выполнение MMX инструкций
WM/M2	Write MMX	Запись результата MMX/MMM умножение 2
M3	Multiply 3	MMX умножение 3
WMUL	Write Multiply  Запись результата MMX умножения
 -----------------------------------------------------------------------

  Pentium Pro/Pentium II/Pentium III

 -----------------------------------------------------------------------
BTB0		Определение адресса следующей инструкции
IFU0..IFU2	Выборка 2 cache linse 32 байта каждая
        нахождение границ инструкций
ID0..ID1	Декодирование инструкций
        (2 simple => 1 mOPS каждая, 1 comples => 4 mOPS за такт)
RAT		Reassign Physical registrers to RAT
ROB Rd		Update ROB (Reorder bufffer)
RS		Reservation station
        (check status bit in mOPS which wait in ROB,
        if more that one ready, select that will be executed)
EX		Execture
ROB Wb		Mark instruction as complete + update ROB
RRF		Retire instruction, Write back results, Free pool entry
 -----------------------------------------------------------------------


50.3. СКАЛЯРНЫЕ И ВЕКТОРНЫЕ АРХИТЕКТУРЫ

        Архитектура
          (классификация Флинна)
          /   |    |   \
        SISD SIMD MISD  MIMD
                                                 Комманда  Данные/команду
SISD	Single Instruction Single Data	 Скалярная  	одна	  одна
SIMD	Single Instruction Multiple Data Векторная	одна	  много
MISD	Multiple Instruct. Single Data   Суперскалярная много     одна
MIMD	Multiple Instruct. Multiple Data Супервекторная много	  много

Классификация Флинна-Джонсона:

  SISD

Скалярная архитектура - в одно время выполняется одна комманда,
которая обрабатывает одну порцию данных (скаляр).

SISD - стандартная архитектура.

  SIMD

Векторная архитектура - в одно время выполняется одна комманда,
которая обрабатывает много порций данных (вектор).

      SIMD
    /     \
 Векторная   Массивно-
         паралельная

Пример Векторной - это суперкомпьютеры CRAY
(Здоровые векторные регистры и ALU. Операция осуществляестся не над всем
векторным регистром, а только над частями помеченными масками.
Используется зацепление операций).

CRAY-1:

  MISD

Суперскалярная архитектура - в одно время выполняется много комманд,
каждая которая обрабатывает одну порцию данных (скаляр).

  MIMD

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

          MIMD
        /    \
   мультипроцессоры  мультикомпьютеры

  Мультипроцессоры

        мультипроцессоры
        /     |         \
          UMA    COMA       NUMA
        /   \               /   \
    шина координаты     CC-NUMA NC-NUMA

UMA  (Uniform Memory Access)
COMA (Cache only memory access)
NUMA (Non-uniform memory access)
CC-NUMA (Coherent Cache NUMA)
NC-NUMA (No-cache NUMA)
NORMA (No Remote Memory Access)

COMA:

NUMA:

ccNUMA:

  Мультикомпьютеры

        мультикомпьютеры
          /        \
        MPP        COW
        /  \
    решетка	   гиперкуб

MPP (Massive Parallelism Processors)
COW (Cluster of workstations)
NOW (Network of workstations)

COW:

MPP:


50.3.1. МАТРИЧНЫЕ ПРОЦЕССОРЫ

THIS SECTION IS UNDER CONSTRUCTION

    Матричные процессоры
     /              \
     систолические    волновые

Систолические - единая синхронизация
Волновые      - как доходит волна данных

Применение матричных процессоров
    Обсчет сложных физических задач (например погоду)

    Быстрое преобразование Фурье
    Цифровая фильтрация
    Матричные вычисления

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

Например перемножение матриц - роль этой операции постоянно растет.

Вычисление полинома:

Поиск в строке:

Умножение матрицы на вектор

Умножение двух матриц:

Что делать если разрядность матрицы больше чем операционное устройство.

      n   n
       n| A | B |   | E | F |     | AE + BG | AF + BH |
    | --+-- | * | --+-- |  =  | --------+-------- |
       n| C | D |   | G | H |     | CE + DG | CF + DH |

Быстрое преобразование Фурье
FFT - Fast Fourier Transorm


50.3.2. ВЕКТОРНЫЕ ПРОЦЕССОРЫ (СУПЕРКОМПЬЮТЕРЫ)

THIS SECTION IS UNDER CONSTRUCTION

Seymour Cray

  Operation chaining


50.3.3. SOFTWARE PIPELINING

THIS SECTION IS UNDER CONSTRUCTION

  Выполнение по предикатам

HP-PA, IA-64

  Программный конвеер

Вращение регистров

    mov	ar.lc = 5 ;;
loop:	ld8	r18 = [16], 8 ;;
    st8	[r17] = r18, 8
    br.cloop	loop

    mov	ar.lc = 5
    mov	ar.ec = 2
    mov	pr.rot = 0x10000 ;;
loop:
 (p16)  ld8	r32 = [r16],8
 (p17)	st8     [r17] = r33, 8
    br.ctop	loop


50.3.3. ОРГАНИЗАЦИЯ ОБРАБОТКИ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

    поток Управления
        Фон Нейман - классическая архитектура
        инструкция выполняется когда ей приходит управление

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

    поток Запросов
        инструкция выполняется когда нужен ее результат
        (и она сама запрашивает результаты у других
                 интсрукций по необходимости)

    поток с управлением по набору условий
        клеточные матрицы элементов


50.4. RISC И CISC АРХИТЕКТУРЫ

В мире царит соотношение 20/80:
20% людей выпивают 80% всего пива в мире.

В типичном компьютере 20% типов инструкций выполняются в течении
80% всего времени работы.

Идея: реализовать только эти 20%, но сделать что бы они были очень
      быстрыми. (Reduced Instruction Set - урезанный набор инструкций.

Архитектура системы комманд
    /           \
  Аккумуляторная    Стековая
       |
   Регистровая
    /     \
CISC    Выделенный
    Load-Store
       |
      RISC
       |
      VLIW
       |
      EPIC

            Архитектура
             /	   |    |    \
           CISC  CRISC  RISC MISC
        сложный		     простой
        набор		     набор
        команд		     команд
            < ------------------
            сложность

CISC  (Common Instruction Set complex)
CRISC (Complexity Reduced Instruction set complex)
RISC  (Reduced instruction set complex)
MISC  (Minimal instruction set complex)
VLIW  (Very Large instruction word)

  RISC

                                            раньше	теперь
    Фиксированная длинна команды			32	32	бит
    Аппаратная реализация комманд за 1 такт
    Суперскалярность				2-3	3-5
    Большое число регистров общего назначения	32	256
    Архитектура регистр-регистр
    Небольшое число режимов адрессации памяти	1-4	3-8
    Небольшое число форматов комманд		1-4	4-10
    Упреждающий доступ к памяти
    Операции с памятью только загрузка/выгрузка
    Устройство управления с жесткой логикой
    Шины данных большой разрядности			64	128,256
    Наличие Write-Buffers
    Существенная аппаратная поддержка ЯВУ

  CISC

    Большое исло машинных комманд, многие из
    которых аналогичны операторам ЯВУ и выполняются
    за много тактов
    Большое число способов адрессации
    Различная разрядность операций (8,16,32 бит)
    Преобладание двухоперандного формата комманд
    Малое количество регистров общего назначения
    Доступ к памяти не только загрузка/выгрузка
    Широкое использование микропрограмм.

    Современные микропроцессоры x86 - имеют частичную RISC архитектуру.

  VLIW

    Фиксированная длинна команды (большая)
    Много регистров общего назначения
    Небольшое число форматов команд
    Несколько примитивных операций в одной команде
    Доступ к памяти только загрузка/выгрузка
    Основная проблема VLIW - усложнение регистрового файла.
    (например если ширина = 3 команды, то регистр должен иметь 6 выходов
     и 3 входа).

  EPIC

    EPIC (Explicitly Parallel Instruction Computing)
    Инструкции хранятся во VLIW
    Но параллелизм задается явно
    Поток инструкций содержит разделители которые
    определяют границы групп команд которые могут
    быть выполнены паралельно.
    (IA-64)

Пример bindles:
        I0    I1    I2
        I0 ;; I1    I2
        I0    I1 ;; I2
        I0    I1    I2 ;;
        I0 ;; I1 ;; I2
        итд.

Пример кода:
        I0    I1    I2		(I0..I4 - паралельно, затем
        I3    I4 ;; I5	         I5..I6 - паралельно, затем
        I6 ;; I7    I8 		 I7..I11 - паралельно)
        I9    I10   I11

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

  VISC

VISC (Variable Instruction Set Complex)

Можно менять набор команд.

Имплементации:
Микропрограммная

Аппаратная
(реконфигурация hardware как в FPGA).


50.5. OUT-OF-ORDER EXECUTION

            Архитектура
           (по потоку выполнения)
         /            |            \
   фон Неймановская       поток данных     поток запросов
   ------------- команда выполняется когда --------------
   при передаче           готовы данные    когда нужен
   ей управления          для нее          ее результат

            Архитектура
              (по запуску команды) Issue
            /        \
         In-Order	Out-of-Order
         в порядке	без проядка

            Архитектура
              (по заканчиванию команды) Completion
            /          \
            In-Order	  Out-of-Order
         в порядке	без проядка

Как выглядит out-of-order execution?

Decoder помещает декодированные инструкции в Instruction Pool,
Исполняющие устройства (execution units) выбирают команды, которые
готовы к выполнению (т.е. их операнды готовы) и исполняют их.
Более позняя команда может исполнится если предидущие не готовы
(таким образом выполнение иден не по порядку (out-of-order).
Retire unit выбирает и удаляет из poolа уже выполненые команды
(в порядке в котором их выдал декодер).

Пример Executon Init for Pentium Pro:
 ----------------------------------------------------------
 Unit	Actions
 ----------------------------------------------------------
 0	ALU
    Mul/Div
    Shift
    FPU
 ----------------------------------------------------------
 1	ALU
    Jumps
 ----------------------------------------------------------
 2	AGU Load
    Load
 ----------------------------------------------------------
 3	AGU Store
 ----------------------------------------------------------
 4	Store
 ----------------------------------------------------------

В современных процессорах x86-архитектуры начиная с Pentium Pro
происходит code-morphing. Сложные x86 команды преобразуются в
простые mOPS команды которые и выполняются.

  Варианты out-of-order

Для нашего примера примем:

    Decoder может декодировать 2 команды за такт.
    Выполнение команд:
        Команда	Execution Unit Время
        I1	1	2
        I2	2	1
        I3	3	1
        I4	3	1
        I5	2	1
        I6	2	1

In Order issue with in-order completion:
(запуск по порядку и завершение по-порядку)

(Конвеер двигается только тогда когда все команды на стадии закончены)
Декодированные I3 и I4 ждут пока выполнятся I1+I2.
I4 ждет когда выполнится I3 (зависимость по ресурсам).
I6 ждет когда выполнится I5 (зависимость по ресурсам).
Общее время = 8.

In Order issue with out-of-order completion:
(запуск по порядку и завершение не по порядку)

(одновременно могут выполняться 2 команды)
Декодированная I4 ждет пока будет место.
I4 ждет когда выполнится I3 (зависимость по ресурсам).
I6 ждет когда выполнится I5 (зависимость по ресурсам).
Общее время = 7.

Out of order issue with out-of-order completion:
(запуск не по порядку и завершение не по порядку)

(все могут выполняться не одновременно)
Общее время = 6.

  Имплементация

Детали Instruction Poolа:

Декодер помещает инструкцию с свободный слот в кольцевом буфере
instruction pool.
Retired pointer показывает откуда можно начать убирать команды
Retire unitу.
Показаны 4 команды находящиеся в состояниях:
    Running	 		(выполняется)
    Complete 		(выполнена)
    Ready to run    	(готова к выполнению)
    Wait for some condition (ждет готовности операндов)


50.6. HYPERTHREADING, MULTIPROCESSING и MULTICORE

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

Идея: два независимых потока комманд используют общий Instruction Pool
(Каждый поток имеет свой Decoder и Retire unit (команды в Poolе
маркированы какому потоку они принадлежат).
Один из потоков является более приоритетным.

Процессор с HyperThreading.

Плюсы:   общий сache (быстрый intercommunication)
Минусы:	 второй поток более медленный
     большая паралельная нагрузка на шину (но меньше чем в DP).

Двухпроцессорная система.

Плюсы:   потоки оба быстрые
Минусы:  общая внешняя шина тормозит

В настоящее время идет тенденция к Multicore (несколько ядер собираются
на одном физическом чипе).

  HyperThreading

Без hyperthreading

Hyperthreading

  Multicore

Hyperthreading

Double core

  Multicore+Hyperthreading

Double core

Double core + Hyperthreading


50.7. CACHE

Память очень медленное устройство по сравнению с процессором.
Современные процессоры работают на частоте 3GHz, а внешняя шина на
частоте 800Mhz т.е. в несколько раз медленнее.

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

Что делать?
Идея: держать некоторую часть памяти к которой обращались последнее
      время внутри процессора (оттуда мы сможем ее взять быстрее если надо).
      Это место (где держат часть) называется cache (тайник).

Принцип:
    подальше положишь, поближе возмешь

Особенно cache актуален для фон-Неймановской архитектуры, т.к. паралельно
с обращениями комманд к памяти идет выборка команд.

  Как работает cache

На чтение:

Процессор просит cache прочитать данные.
Если данные есть в cache то cache их быстро возвращает
Если же данных нету то cache выбирает их из памяти,
записывает их в себя и возврощает процессору.

    Tef = p * Tcache + (1-p) * Tmem

    Tef    - эффективное время
    Tcache - время доступа к cache
    Tmem   - время доступа к памяти
    p      - вероятность поподания в cache (0..1)

На запись:

        Cache
           (на запись)
           /    \
      Write-through  Write-back
    Сквозная запись  Отложенная запись

Сквозная запись:

Данные пишутся в cache и одновременно уходят на шину.

Отложенная запись:

Данные пишутся только в cache. Cache сам решает когда и какие
данные переписать из cache в память.

Примеры зависимости параметров на тесте SPEC2000

  Организация cache

THIS SECTION IS UNDER CONSTRUCTION

    о Direct Mapped
    o Full associative
    o Set associative
    o Sectored

  Direct Mapped

Direct Mapped (прямое отображение):

    Адресс строки i
    Адресс памяти j

    i = j MOD m 	(m - общее число строк в памяти).

    +------------+ +------+ +--------+
    |    TAG     | | LINE | |  BYTE  |	Адресс
    +------------+ +------+ +--------+
               |                 |
               +-----------------+
            не хранится в cache

          Cache
        +-----------+             +---------------------------+
        |           | ----------->| только блок ADDR % M = i  |
        +-----------+		  +---------------------------+
        |	    |
        +-----------+
        |	    |
        +-----------+

с длинной строки 16 bytes

  Full Associative

Full Associative (полноассоциативное отображение):

    +-------------------++-----------+
    |      TAG	    ||  BYTE     |	Адресс
    +-------------------++-----------+
                     |           |
                     +-----------+
                не хранится в cache

          Cache
        +-----------+             +---------------------------+
        |           | ----------->|     любые блоки           |
        +-----------+		  +---------------------------+
        |	    |
        +-----------+
        |	    |
        +-----------+

  Set Associative

Set associative (множественно-ассоциативное отображение):

    Разбита на подмножества (в строке несколько ways)

    +------------+ +------+ +--------+
    |    TAG     | | LINE | |  BYTE  |	Адресс
    +------------+ +------+ +--------+
               |                 |
               +-----------------+
            не хранится в cache

    Адресс строки i
    Адресс памяти j

    i = j MOD m 	(m - общее число строк в памяти).
    но в каждой строке несколько ways.

           Cache
           2 way
        +-----+-----+             +---------------------------+
        |     |     | ----------->| только блок ADDR % M = i  |
        +-----+-----+		  +---------------------------+
        |     |	    |		    но для них 2 входа
        +-----+-----+		    т.е. может хранить 2 блока
        |     |	    |		    одновременно
        +-----------+

Пример 2 way:

Почему берут средние биты для индекса LINE?

  Протоколы состояния cache

           Архитектура cache
        (протокол сотояния линии)
            /          	   \
        однопроцессорно   многопроцессорно
        ориентированный	  ориентированный
        SI

  SI

В однопроцессорно ориентированном cache только процессор в вычислительной
системе имеет cache - все остальные не имеют.

Поэтому элементы в cache имеют сосотояния:
    I - Invalid	 недействительный
    S - Shared       разделяемый

  MESI

В многопроцессорной системе cache имеет на только процессор но и другие
процессоры и необходимо осуществлять когерентность cache (т.е. соответствие
тому что должно быть в системе.

Существует много дисциплин для многопроцессорно-ориентированного cache,
несомненно самая популярная из них MESI протокол:

В MESI протоколе элемент может принимать одно из 4 состояний:
    M 	Modified	Измененный
    E	Exclusive	Измененный только в текущем процессоре
                    и не выведенный еще на шину
    S	Shared		разделяемый
    I	Invalid		недествительный

Другие многопроцессорно ориентированные дисциплины:

  MOESI

  Write-once

    Write-once protocol
    Synapse protocol

  Berkeley

        Berkeley protocol

  Illinois

        Illinois protocol

  Firefly

        Firefly protocol

  Dragon

        Dragon protocol

        Архитектура cache
        Дисциплина замены блоков
        /  	     |             \
     FIFO       LRU            RAND
     (First in   (Last Recently    (Random)
     First out)      Used)
           /	  \
        точный    приблеженный
        LRU	  LRU

FIFO - заменяется тот элемент в линии которая была выбрана первой.
RAND - заменяется случайный элемент в линии
       (как это сделать - есть счетчик который прибавляет по 1 каждый
    такт процессора, независимо от доступа к памяти,
    его содержимое - это индекс элемента)
LRU  -  Наиболее долго не используемый
    заменяется тот элемент к которому обращались раньше всего.

  Архитектура Cache

    Cache
    |
    +-- Виртуальный
    |
    +-- Виртуальный с физическими tags
    |
    +-- Физический

Виртуальный cache

Виртуальный cache с физическими тэгами

Физический cache

  Эксклюзивность

    Cache
    |
    +--- эксклюзивный
    |
    +--- неэксклюзивный
    |
    +--- инклюзивный

Эксклюзивный cache - если информация есть на каком-то уровне cache,
то она отсутствует на других уровнях.
Плюсы:	можно хранить больше информации
Минусы: дополнительное оборудование для поддержки экслюзивности
    Info = SUM(Li)

Инклюзивный cache - в Li всегда содержится все то что есть в Lj, если i > j.
    Info = Lmax

Неэксклюзивный cache - в Li может содержаться, а может не содержаться
информация из Lj.

  Иерархия памяти

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

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

Cache занимает много места на кристалле, поэтому возможны варианты когда
на чипе хранятся только tags, а данные хранятся во внешнем cache.
Пример Sun UltraSPARC IV (двухядерный процессор, в котором L2 tags внутри,
а данные снаружи на особой шине).

  Особенности кэширования для MultiCore

Сейчас идут уже и обратные тенденции - типа запрятить одно из ядер, а его
cache передать другому.


50.7.1. CACHE SNOOP

THIS SECTION IS UNDER CONSTRUCTION

  Source Snoop

  Snoop on write

  Cache forwarding


50.7.2. МИКРООПЕРАЦИИ И КЭШИРОВАНИЕ КОДА

THIS SECTION IS UNDER CONSTRUCTION

  Кэш инструкций

Обычные RISC процессоры все хорошо - инструкции фиксированной длинны и
выполняются как правило за 1 такт - все хорошо.

В случае же CISC процессоров у нас сложная система комманд переменной длинны.
Поэтому с целью минимизации времени работы code cache стал опускаться по
конвееру ближе к выполняемым устройствам.

  Кэш полудекодированных инструкций

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

  Кэш микроопераций

Затем пришел out-of-order execution. Процессоры стали преобразовывать команды
во инструкции для внутренного ядра (mOPS).

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

Пример блока декодирования для Intel Core:

Соответственно cache инструкций сместился еще дальше по конвееру и стал хранить
уже mOPS.

  Trace кэш

Дальнейшее развитие привело от mOPS-cache к Trace-cache, который уже содержал
не микрооперации, а последовательности микроопераций которые не прерывались
входящими/исходящими переходами (traces), и будучи запущенными выполнялись
полностью, что повышало производительность.

Организация T-cache в сравнении с I-cache.
Старшие биты адресса инструкции это Tag, младшие Set.
(т.е. N-way associative)

Кроме того trace-cache может использоватся для развертки коротких циклов:

  VLIW mOPS

Другой подход был использован в процессорах Transmeta Crusoe. Там использовался
встроеенный в процессор Firmware компилятор, который преобразовывал входящие x86
комманды в native VLIW комманды процессора. Естественно code cache хранил
именно эти комманды.

Форматы VLIW комманд Crusoe:


50.8. ПРЕДВЫБОРКА

THIS SECTION IS UNDER CONSTRUCTION

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

Типичный cache L1 код+дата:

Program Flow для условного перехода.

В L1 code cache можно хранить декодированные команды
(это убыстряет их выполнение)


50.9. ПРЕДСКАЗАНИЕ ПЕРЕХОДОВ

Так выглядет конвеер в случае непредсказанного условного перехода:
(Prefetcher сбрасывается).

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

Что бы правильно заполнять prefetcher надо уметь предсказывать условные
переходы. Для этого служит специальный узел называемый BTB (Branch Target
Buffer).
Этот узел является некоторым аналогом cache, но для условных переходов.
Он содержит:
    o Адресс инструкции перехода
    o Предсказание будет ли переход или нет
По запросу от prefetchera он выдает предсказание для указанного адресса
где находится инструкция перехода.

Histeresis:

Saturation:

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

    o Точно не будет   (по умолчанию если неизвестно)
    o Скорее всего не будет
    o Скорее всего будет
    о Точно будет

Вход в BTB имеет формат:

    +-----------------+----------+
    | адресс JUMP	  | история  |
    +-----------------+----------+

как правило BTB имеет ассоциативную структуру типа cache.

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

indirect переходов

возвратов из функций (call stack).

  IA-64

IA-64 Очень интересно с точки зрения команд условных переходов.
Команды содержат в себе hints:

    .sptk	Static predicted taken
    .spnt	Static predicted non-taken
    .dptk	Dynamic predicted taken
    .dpnt	Dynamic predicted non-taken
    -----------------------------------------
    .few	Preload few lines in cache code
    .many	Preload many lines in cache code
    -----------------------------------------
    none	Not-clear dynamic branch cache
    .clr	Clear branch cache


50.9.1. ОТЛОЖЕННЫЕ ПЕРЕХОДЫ

(X - инструкция перехода)
(A,B - инструкции плсде перехода когда он выполнен).

Условный переход сбрасывает конвеер при своем выполнении.
Можно ли как-нибудь минимизировать это влияние?

Да, для этого служат отложенные переходы (Delayed branches).
Они используются на RISC процессорах (например HP-PA).

Идея:
    Выполняется переход (но не происходит сброса конвеера,
    а начинается предвыборка с уже нового адресса, а команды
        которые сидят в конвеере выполняются независимо от того
    будет переход или нет:
        (Если нам нечего поставить то можем окно отложенного
         перехода заполнить командами NOP (No Operation))

Пример HP-PA
    LDW	0x20(r30), r2
    COMI    B, >10,r2,main+80
    LDW	0x24(r30), r3     	// выполняестся в оюбом случае
                    // был выполнен переход или нет

    +----------+
    |   ...	   |
    +----------+
    | условный |
    | переход  |
    +----------+  ---+
    | команды  |     | окно отложенного перехода
    |          |     | (эти команды выполнятся по любому)
    +----------+  ---+
    |  ...     |
    +----------+

Переход не выполнен:

Переход выполнен:

Как мы видем конвеер не стоит.


50.10. ПЕРЕИМЕНОВАНИЕ РЕГИСТРОВ И РЕГИСТРОВЫЕ ОКНА

  Переименование регистров

Переименование регистров (registers renaming) технология цель которой
минимизировать задержку конвеера при зависимости по данным.

Зависимости по данным:

                    Register renaming
    WAR	(Write after Read)	Remove problem
    RAW	(Read  after Write)	No changes
    WAW	(Write after Write)	Remove problem

Идея: физичеких регистров больше чем программных регистров процессора
      мы говорим какой физичекий регистр в какое время отвечает за
      какой програмный регистр процессора.
      (как правило Register renaming используется в out-of-order
       execution).

 ----------------------------------------------------------------------
clk S  num  instruction		comment
 ----------------------------------------------------------------------
[1]EX	1:  mov  R1,R2
[2]EX	2:  mov  R2,1234h	// WAR
[3]WB				// нельзя исполнять пока (1) не исполнится
                // потому что мы испортим R2
[4]EX	3:  mov  R3,R2		// RAW
[5]WB				// нельзя исполнять пока (2) не исполнится
                // нужен результат (2)
[6]EX	4:  mov  R3,R4		// WAW
                // нельзя исполнять пока (3) не исполнится
                // a то (3) испортит нам R3
 ----------------------------------------------------------------------

Распределяем регистры:
 ----------------------------------------------------------------------
                        IR1 IR2 IR3 IR4 IR5 IR6
 ----------------------------------------------------------------------
    1:  mov  R1,R2                      R1  R2      R4
    2:  mov  R2,1234h	                    R2
    3:  mov  R3,R2		// RAW                      R3
    4:  mov  R3,R4		// WAW                          R3
 ----------------------------------------------------------------------

Транслируем:
 ----------------------------------------------------------------------
clk S  num  instruction		comment
 ----------------------------------------------------------------------
[1]EX	1:  mov  IR1,IR2
[1]EX	2:  mov  IR3,1234h
[2]WB
[3]EX	3:  mov  IR5,IR3	// RAW
                // (3) ждет пока (2) будет готов
[1]EX	4:  mov  IR6,IR4
 ----------------------------------------------------------------------

Мы убрали 2 зависимости: В результате конвеер стоит гораздо меньше,
т.к. независимые инструкции мы можем исполнить паралельно.

  Регистровые окна

Регистровые окна (Register Window)

Окно регистров
    Parameters
    Local
    Temporary
        циклические структуры

Окна фиксированного размера (SPARC)

Окна переменного размера (IA-64)


50.11. АДРЕСНОЕ ПРОСТРАНСТВО И ВИРТУАЛЬНАЯ ПАМЯТЬ

THIS SECTION IS UNDER CONSTRUCTION

        Адресное пространство
         /  		\
        сплошное            сегментированное

    +-----------+		+-------------+
    |	    |		|	      |
    |	    |		|+-----------+|+< -------+
    |	    |		|| окно	     |||         |
    |	    |		||	     |||         |
    |	    |< --+	||	     ||+< --+    |
    |	    |    |	||	     ||     |    |
    |	    |    |	|+-----------+|     |    |
    |	    |    |	|	      |     |    |
    |	    |    |	|	      |     |    |
    +-----------+    |	+-------------+     |    |
                     |                          |    |
    +-----------+    | 	+-----+-------+     |    |
    |  Offset   |----+      | Seg | Offset|-----+    |
    +-----------+           +-----+-------+          |
                   |                     |
                   +---------------------+

Виртуальная память:

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

         VIRTUAL			  PHYSICAL
     +-----------+			+-----------+
    |	    |----------+	|	    |
    +-----------+          |        +-----------+
    |           |       +--=------->|	    |
    +-----------+       |  |        +-----------+
    |	    |       |  +------->|	    |
    +-----------+	    |		+-----------+
    |	    |-------+
    +-----------+
    |	    |------> NOT PRESENT
    +-----------+
    |	    |
    +-----------+
    |	    |
    +-----------+

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

Direct-Mapped Paging:

Associative Paging:

Set Associative Paging:

Рассмотрим виртуальную память на 386 процессоре:

             10 bit	     10 bit	     12 bit
        +---------------+-------------+-----------------+
        |     DIR	|    PAGE     |    OFFSET       |
        +---------------+-------------+-----------------+
              |	                 |                  |
 +----------+         |                  |                  |
 |    CR3   |         V                  |                  |
 +----------+        INDEX in            |                  |
    |                                |                  |
    |	PDT (Pages               |                  +---------+
    |       Directory Table)         V                            |
    \---->+----------------+        INDEX in                      |
          |	   ....        |                                      |
          +----------------+         PT (Pages Table)             |
          |    PT desc.    |------>+-------------------+          V
          +----------------+       |      ......       |      OFFSET in page
          |    ....        |       +-------------------+
          +----------------+       |    Page desc.     | ---> +-----------+
          |	 	       |       +-------------------+	  | Page in   |
          |		       |       |       .....       |      | memory 4K |
          |		       |       +-------------------+      +-----------+
              +----------------+

Память организована в виде страниц размером 4K.
Системный регистр CR3 процессора указывает на таблицу директории страниц.
Каждый вход в этой таблице указывает на таблицу страниц.
А каждый вход в таблице страниц указывает на страницу в памяти.

Типичные аттрибиты страниц в таблицах страниц:

    o Существует/не существует
    о Присутствует в физической памяти
    o Была ли модифицированна
    o Разрешено ли чтение/запись/выполнение
    о Можно ли cachировать и как
    o Уровень доступа (пользователь/система)

  TLB

Операция вычисления физического адресса по виртуальному занимает очень
много времени (2 обращения к памяти на 386).
Что бы повысить производительность используется TLB
(Translation Lookahead Buffer) - это типа cache но не для данных, а для
адрессов страниц.

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

Собственно процессор не обязан работать с таблицами страниц аппаратно
Некоторые архитектуры (Alpha) на Page Fault вызывают exception, а
операционная система сама ходит по таблицам и результат записывает через
специальные системные регистры в TLB.

Полный цикл доступа к памяти:

А вот как выглядет cache и TLB в Opteron


50.12.1. СПЕКУЛЯТИВНАЯ ЗАГРУЗКА И ДРУГИЕ ХИТРОСТИ С ПАМЯТЬЮ

  Спекулятивная загрузка

THIS SECTION IS UNDER CONSTRUCTION

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

Например обход списка
    Делаем спекулятивную загрузку следующего элемента в списке
    пока обработает текущий - следующий уже будет в cache

    Или например проход по таблицам в базах данных

    LoadSpec
    .....

    DO_SOME_OTHER_ACTIONS
    .....
    WaitLoadSpecReady

  Memory Hints

THIS SECTION IS UNDER CONSTRUCTION

    Загрузка/Запись
        не в cache (not temporary)
        (это позволяем минимизировать засорение cache)
            MOVNTI
            MOVNTDQ
            PREFETCHNTA
        в определенный уровень cache
            PREFETCH0
            PREFETCH1
            PREFETCH2
        во все уровни cache
    Сброс линии cache
        (если мы знаем что больше не понадобится)
        CLFLUSH

  Чередование банков памяти

THIS SECTION IS UNDER CONSTRUCTION

    +------------+
    |	     |          +------+
    | Memory     |----------|Bank 0|
    | controller |		+------+
    |	     |
    |	     |          +------+
    |	     |----------|Bank 1|
    |	     |		+------+
    +------------+

Посколько обращения в основном идут подряд (выборка, загрузка линии cache).

  Write Buffers

В принципе процессору не обязательно ждать пока выполнится операция записи
до конца (особенно для низкоскоростных устройств), он может ее сбросить
в Write Buffers (которые находятся либо в BUI, либо внутри Chipset,
либо и там и там. Это повышает скорость.

        +----------+
        | +------+ |
        | | WB   | |
CPU пишет в WB	| +------+ |  Из WB асинхронно от CPU пишут дальше
 ------------>	| = ...  = | ------------------->
        | +------+ |
        | | WB   | |
        | +------+ |
        +----------+

Понятно, что если все Write Buffers заполнены процессор будет ждать.
Для сохранения когерентности:
    Все операции с Write Buffer идут in-order
    (т.е. Первый помещен в WB, первый уйдет на шину)
    Любое чтение будет ждать пока все Write Buffers не будут записаны.

  Быстрые spin-locks

TODO: Быстрые спин-локи
      MONITOR/MWAIT
      идеи.


50.13. ЗАЩИТА

          +------------------+
      |                  |
      |	+-------+    |
      |	|  User |    |
      |	+-------+    |
          |     Supervisor   |
      +------------------+

Надо защитить операционную систему от прикладных программ
(и программы друг от друга).

Объекты памяти
    Сегменты
    Страницы
        Доступ на чтение
        Доступ на запись
        Доступ на выполнение
            Соответственно кольцу защиты
    Порты ввода/вывода

Привелигированные инструкции
    Ввод Вывод
    Остановка процессора
    Работа с системными регистрами

Обьекты выполнения
    Задачи
    Прерывания
    Шлюзы
        уровень привелегий для доступа
        правила

Реализация правил возлагается на архитектуру.
Например в HP PA часть адрессных пространств доступна USER программам
по определению, а остальные только SUPERVISORу.

RULE #1: Должно быть невозможно передать управление OS, кроме как в
     предопределенной точке входа.

    User Frame      Supervisor frame

    |     |		|      |
    |     |         +------+
    +-----+    +--->|  P   |
    | P   |----+    +------+
    +-----+         |RetAdr|
    |     |         +------+
    |     |         |      |

С целью повышения надежности разные кольца используют разные stacks.
Потому что USER задача может испортить stack.
И при переключение контекста часть стека копируется в stack другово кольца.

Кольца защиты

i286

Кольца защиты:

Правила доступа:

Шлюзы:

Capacity-based systems

THIS SECTION IS UNDER CONSTRUCTION

iAPX432

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

TODO: Схема дескрипторного доступа в iAPX 432

Segment:

Segment Descriptor:

Access Descriptor:

Call:


50.14. ТЕНДЕНЦИИ В ENVIRONMENT

Тенденции в CPU programming-environment.

Базовое целочисленное ядро
    + FP		(RISC)
    + векторные целочисленные инструкции	(MMX)
    + векторные FP инструкции		(SSE/SSE2)
        + команды иерархии памяти		(SSE2)

    матричные команды
    зацепление операций

Регистр версии процессора
    Удобство определять тип и возможности процессора прямо
    а не базируясь на косвенных признаках

TODO: Пример косвенного определения для x86
    и пример CPUID.

Счетчики производительности

    Time Base Facility	(Time stamp counter)
        каждый такт увеличивается на 1
        (минусы: когда процессор управляет своей частотой динамически,
             время тактов бывает различное)
    Performance monitoring
TODO: Примеры событий и регистров по их управлению

Управление регионами памяти
    Cached Regions Controls

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

    Оперативная память
    Регистры ввода/вывода отображенные в память
    видеобуфер

Очевидно что эти регионы должны иметь как минимум разные политики кэширования
например память кэшировать на запись хорошо,
видеобуфер кэшировать на запись плохо, а на чтение хорошо (если только его не
изменяет какой нибудь 3D engine).
Регистры ввода/вывода кэшировать просто нельзя.
BIOS который копируется из ROM в оперативную память для быстродействия
может кэшироваться, но не должен модифицироваться.

Кроме того современные процессоры поддерживают out-of-order execution,
а порядок операций ввода/вывода в некоторых случаях критически важен

    -------------------------------------------------------------
                         Speculative Memory
                              Cache	WB	Read     Ordering
    -------------------------------------------------------------
    Write Protected		Yes	No	Yes      Speculative
    Write Back		Yes	Yes	Yes	 Speculative
    Write Through		Yes	No	Yes	 Speculative
    Write Combining		No	No	Yes	 Weak
    Uncachable		No	No	No	 Strong
    -------------------------------------------------------------

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

TODO: Примеры

Uncached:

Write Combining:

Write Through

Write Back


50.15. УРОВНИ ПАРАЛЛЕЛИЗМА

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

    Система/Сеть		Multicomputer       слабые связи   линки связи
    Программа		Multiprocessor                     общая память
    Команда			Superscalar                        общий cache/regs
    Данные			Vector
    Разряды данных		------------------- сильные связи

На каждом из уровней возможнa архитектура:
        последовательная
        конвеерная
        паралельная
        паралельно-конвеерная


50.16. ВИРТУАЛИЗАЦИЯ

С ростом паралельности растут ресурсы и их хочется использовать
Кроме того объем разного softa растет
Идет тенденция к запуску множества копий а также различных операционных
систем на одном компьютере. Например VMware.
Для ускорения этих процессов в микропроцессоры вводят поддержку для
виртуальных машин. AMD Pacifica, Intel VMX.

Вообщето это было еще в IBM/370 ;)

    +---------+---------+---------+
    |   VM    |   VM    |	VM    |
    |         |         |         |
    +---------+---------+---------+
    |           Host              |
    +-----------------------------+

Это сводится к поддержке иерархии трансляции памяти из VM в Host machine,
а так же среды и комманд передачи управления из/в VM/Host.

Как правило ресурсы Host machine делятся на группы, каждая из групп может
принадлежать какой нибудь виртуальной машине.

TODO: Примеры двойной страничной трансляции и таблиц для виртуализации
      в Intel Vanderpool и AMD Pacifica.


50.17. АППАРАТНАЯ ПОДДЕРЖКА ОТЛАДКИ

THIS SECTION IS UNDER CONSTRUCTION

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

    Single Step mode
    Однобайтовая команда Trap для отладки
    Отладочные регистры
    ICE

  Single Step Mode

Ставится сооветствующий флаг в регистре флагов, после этого процессор
после каждой инструкции будет вызывать Debbuging Exception
(в процессе вызова exception регистр флагов будет сохранен (как правило в стеке),
а бит отвечающий за single step будет сброшен.
После возврата из exception содержимое регистра флагов будет востановлено
и снова будет single step.

  Однобайтовая команда Trap

Отладчик может ставить после интересующей его инструкции однобайтовую (CISC)
или стандарнтного размера (RISC) команду которая вызывает Debbuging exception.

Например для x86 - это команда:

    CCh	INT 3

  Отладочные регистры

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

TODO: Примеры отладочных регистров для нескольких семейств CPU

  ICE

    ICE (In Circuit Emulator). После выполнения инструкции процессор
останавливает работу аппаратно, а содержимое регистров и внцтренних структур
можно получить и/или изменить через специальные входы/выходы.


50.18. МИКРОКОНТРОЛЛЕРЫ

THIS SECTION IS UNDER CONSTRUCTION

Компактный ISA
Интеграция переферии

Например классический 8051

или PIC

Подсистема таймеров


51. АРХИТЕКТУРА ВВОДА-ВЫВОДА

THIS SECTION IS UNDER CONSTRUCTION

  Адрессное пространство ввода/вывода

             Ввод/Вывод
            |
       +------------+--------------+
       |            |              |
    Ячейки	       Ячейки      Специализированное
    в пространстве       в         встроенное
        памяти         I/O space   Hardware
                           (Пример: 80186,
                    или serial port на 8085)

               Ввод/Вывод
        (в архитектуре общая шина)
              |
     +----------------+-------------------+
     |                |                   |
    PIO		 DMA		Аппаратным путем
     программным       аппаратным	через специализированный
     путем через       путем через 	процессор ввода/вывода
    CPU		 DMA		(пример: 8089)
             |                                    |
             +------------------------------------+
            По окончанию может быть запрос на прерывание

                 Ввод/Вывод
          (в архитектуре без общей шины)
                |
             +------+---------+
             |                |
        Процессорная	 Коммутирующие
           сеть		 переключения

  PIO и DMA

PIO:

Чистое PIO с блокированием:

PIO с ожиданием прерывания:

DMA:

Возникают проблемы при различном размере адрессного пространствы системы и
bus-master карты:

Наиболее известные примеры:
    ------------------------------
        система   шина	комментарий
    ------------------------------
    2^32	  2^24	  ISA (16-бит)
    >2^32	  2^32	  PCI (32-бит)
    ------------------------------
поэтому операционной системе приходится делать двойную буфферизацию
размещая буфера в младшей памяти, что бы карта смогла осуществить в них ввод/вывод.

Вторая пробема которая возникает это Alignment проблема
Как правило современные Bus Master devices пишут данные как минимум квантами по
32- или 64- бита. И соотвествующие буфера должны быть выравнены (потому что карта не может
сделать доступ по байту, это уменьшает размер Hardware логики в устройстве).

Поэтому в таких случаях операционная система тоже делает двойную буферизацию.

  Scatter/Gather

Проблема: двойная буфферизация

  DMA burst

  Упреждающее чтение и буферизованная запись

  Последоватеьные и паралельные шины

  Хабовая архитектура

Hub - буферизирует

  Шины ввода вывода

Например SCSI:
    Возможна ситуация когда CD-Recorderу дают команду, он выдает команду
    CD-ROM и копирует с него данные на себя. При этом все происходит
    внутри I/O Bus (в данном случае - SCSI) и процессорная шина
    совершенно не загружена данными.


51.1. ГИПЕРКУБЫ

THIS SECTION IS UNDER CONSTRUCTION

  3D

  4D

  5D

  Как это выглядет


55. ОСНОВЫ ПЕРЕДАЧИ И ХРАНЕНИЯ ДАННЫХ

В общем виде Workflow может быть представлен в виде:

Кодирование источника:
    Cжатие данные
    смотри секцию 71

Криптографическое кодирование:
    Шифрование данных
    смотри секцию 72

Кодирование канала:
    Расширение кодового алфавита, для того что бы исправлять ошибки
    Коды корректирующие ошибки
    смотри секцию 16

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


55.0. АНАЛОГ И ЦИФРА

В зависимости от того какими сигналами мы хотим передавать данные
используются разные методы:
--------------------------------------------------------
Данные		Сигналы		Передача
--------------------------------------------------------
Цифровые	Цифровые	Логическое кодирование
Цифровые	Аналоговые      ASK,FSK,PSK
Аналоговые	Цифровые	PCM
Аналоговые	Аналоговые	AM,FM,PM
--------------------------------------------------------

Обработка данных


55.1. ПОСЛЕДОВАТЕЛЬНАЯ И ПАРАЛЕЛЬНАЯ ПЕРЕДАЧА/ХРАНЕНИЕ ДАННЫХ

            Передача/Хранение
              /        \
           паралельное    последовательное

    Данные хранятся и передаются в основном в последовательном формате.
Хотя возможно и паралельное хранение/передача.

Паралельная передача:

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

Последовательная передача:

Типичная диаграмма Size/Time:

        ^
   Size	|			передача 8 бит
      4	|--+			(паралельная по 4)
    |XX|
         |XX|
    |XX|
    |XX|
    +-------------->
           2           Time

        ^
   Size	|
    |			передача 8 бит
    |			последовательная
          |
      1	|--------+
    |XXXXXXXX|
    +-------------->
             8     Time


55.1.1.ПАРАЛЕЛЬНО-ПОСЛЕДОВАТЕЛЬНЫЕ ПРЕОБРАЗОВАТЕЛИ

THIS SECTION IS UNDER CONSTRUCTION

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

(В секции 13.2 они описаны детально)

           DATA_IN
                  | | | | |
          V V V V V
        +-------------+
     CLK ---->  |	      |  -------> DATA_OUT
        +-------------+

        +-------------+
     CLK ---->	|	      |  <------- DATA_IN
        +-------------+
         | | | | |   |
         V V V V V   V
         DATA_OUT    READY

Пример последовательно-паралельного регистра


55.2. ПОЛОСА ПРОПУСКАНИЯ

Одно из основных понятий для передачи данных - это полоса пропускания
Полоса пропускания - это полоса частот, пригодных для передачи сигнала.
(Например для стандартной телефонной линии: 300 - 3400 Гц).
Полоса пропускания:

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

    SNR = Pсигнал / Pшум

    SNR     - (Signal-Noise Ration) - отношение сигнал-шум.
    Pсигнал - мощность сигнала
    Pшум    - мощность шума

Формула Шенона

Формула Шенона описывает максимальную возможную (теоретически) полосу
пропускания канала.

    C = B * log2(1 + SNR)

    C - пропускная способность канала (бод)
    B - ширина полоса пропускания канала (Гц)

Теорема Найквеста

    C = 2 * B * log2(M)

    M - число дискретных уровней напряжения

Практический пример:
    Телефон
        полоса пропускания телефонного канала узка
        т.к. ее режут на станции когда пересылают дальше.
    Но полоса пропускания медной линии до станции (последняя миля)
    гораздо больше.
    И ее и используют - ADSL.


55.2.1. ЧТО ТАКОЕ ДУПЛЕКС

            Связь
         /    |     \
           /      |       \
         /        |         \
    Симплексная  Полудуплексная  Дуплексная
     Simplex     Half-duplex       Duplex

Симплексная - передают сигнал только в одном направлении
          (приемник и передатчик не могут менятся местами)

Полудуплексная - передают сигнал в одно время только в одном направлении
         (но приемник и передатчик могут менятся местами).

Дуплексная - одновременно передается сигнал в разных направлениях
             (это достигается одновременной передачей на разных частотах).


55.3. РАЗВЯЗКИ

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

  Гальваническая развязка

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

Прием:
    изменение тока в линии порождает электромагнитное поле,
    которое индуцирует ток в индуктивности устройства.

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

  Оптическая развязка

В принципе транформаторные развязки это не единственное такое средство.
Еще существуют оптические развязки (они тоже гальванические):

Пример оптической гальванической развязки:

    ------------+                             +---------------
        |                             |
    +----------------+     свет    +-----------+
    | Фотодиод или   |  < ------   | светодиод |
    | фототранзистор |  < ------   |           |
    +----------------+             +-----------+
            |			      |
    ------------+		              +---------------

Главное в развязках, что устройство не подключенно электрически к линии напрямую.


55.3.0. ДИФФЕРЕНЦИАЛЬНАЯ ПЕРЕДАЧА СИГНАЛОВ

THIS SECTION IS UNDER CONSTRUCTION

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

RS-232 - обычный
RS-422 - дифферинцеальный

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

Разница (диф. сигнал):

Не путайте дифференциальную передачу данных с дифференциальным
кодированием:
    при дифференциальном кодирование
        при переходах 0-1, 1-0  на выходе 1
        при отсутствии переходов (0-0,1-1) на выходе 0.

Пример дифференциального кодера/декодера:


55.3.1. КОММУТАЦИЯ

THIS SECTION IS UNDER CONSTRUCTION

            Тип соединений
            / 	\
          Коммутация   Коммутация
          каналов      пакетов
                   (порядок передачи не гарантирован)

Звонили ли вы Вы по телефону?

  Коммутаторы

Коммутирующие элементы
Бета элемент

Коммутационные сети

Тасовка (Shuffle)

Баньян

Omega

Дельта

Гамма

Каппа

Сеть Бенеша

Базовая линия

N-мерный куб

Batterfly

Batterfly-16:

сеть Клоса

Треугольный ячеистый коммутатор


55.3.2. ФИЗИЧЕСКАЯ ТОПОЛОГИЯ

THIS SECTION IS UNDER CONSTRUCTION

          Система связи
        /        \
    Point-to-Point   Point-to-Multipoint

Примитивная топология сети

     C      C
       \  /
    HC  		Star		Звезда
      /   \
    C      C

   C - C - C - C - C	Line		Линия

      C
     / \
    C   C		Ring		Кольцо
     \ /
      C

  =--+-------+---+-=	Common Bus	Общая шина
     |       |   |
     C       C   C

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

    C  C  C   C  C  C
     \ | /     \ | /
       HC       HC 	    Tree	Дерево
              \   /			(как правило нижние ветви более
        HC			 производительные)

      C  C    C    C
       \ |    |  /
       C -- HC -- HC -- C   Mesh	Сеть
              \   /
        HC
          / | \
         C  C C


55.3.3. УПЛОТНЕНИЕ СИГНАЛОВ

THIS SECTION IS UNDER CONSTRUCTION

Пропускная способность каналов различна.
А хочется использовать ее по максимуму.
Например через Атлантику лежит оптоволокно, и по нему передаются
сразу десятки тысяч телефонных разговоров.
Для этого делают уплотнение сигналов:

    -----+                        +------->
         |   ==================   |
         +-->  -------------->  --+
    -------->  -------------->  ---------->
         +-->  -------------->  --+
         |   ==================   |
    -----+                        +------->

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

                ===============
            +-->  ---------->   --+
            |   ===============   |
    --------+                     +----->
            |   ===============   |
            +-->  ---------->   --+
            ===============

    Уплотнение сигналов
        /        |        \
 частотное    временное   волновое

  FDM

Частотное уплотнение (FDM - Frequency Division Multiplexing)

  TDM

Временное уплотнение (TDM - Time Division Multiplexing):

  WDM

Волновое уплотнение (WDM - Wave Division Multiplexing):
    Фотоны друг с другом не взаимодействуют
    Мы можем по одномц оптоволокну передавать свет с разной длинной
    волны. А затем разделять на линзе.

    DWMW (Dense WMW) - > 32 каналов
    В настоящие время достигнута скорость порядко терабайт/секунду


55.3.4. СРЕДЫ ОБЩЕГО ДОСТУПА

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

  FDMA

FDMA 	Frequency Division Multiple Access
        разные станции на разных частотах

  SDMA

SDMA	Space Division Multiple Access
        в огороде бузина, а в Киеве дядька
        все они в реальном мире, но друг другу не мешают
        т.к. разнесены в пространстве.
        105.2 FM - у нас одно, в NY - другое, в LA - третье

Реально делают SDMA + разделение частот по направлениям.

Только SDMA:

SDMA + частотное разделение по направлениям

  TDMA

TDMA 	Time Division Multiple Access
            разные станции в разное время

    TDMA-FDD TDMA with Frequency Division Duplex.
        станция передает только в свой слот времени
        и принимает только в него одновременно на разных
        частотах

    TDMA-TDD TDMA with Time Division Duplex.
        станция принимает и передает на одной частоте
        только в свои слоты времени но не одновременно.

  CDMA

CDMA	Code Division Multiple Acess (with very large bandwidth)
        станция использует полосу частот гораздо шире чем ей надо

  CDMA-FH

        FH (Frequency Hoping)
            со сменой частоты
            [BlueTooth]
CDMA-FH:

  DS-CDMA

        DS-CDMA (Direct Sequence CDMA)
            Пересылается широкий спектр содержащий сигналы
            сразу для нескольких станций.
            Станция делает преобразование Фурье умножая
            принятый сигнал на последовательность уникальную
            для станции.
            Важно чтобы эти последовательности были ортогональные
            или почти ортогональные.
            [IEEE 802.11]
DS-CDMA:

DS-CDMA посылка:

DS-CDMA прием:

Процесс формирования кодов на посылку (DS-CDMA):

Формирование несущей в DS-CDMA:

  OFDM

        OFDM	Orthogonal Frequency Division Multiplexing
            сразу передаются данные для всех на разной частоте
            Приемники выделяют данные на своих частотах используя
            преобразование Фурье.
            Это делается путем умножения на свою частоту.
            [смотри раздел 71.2.1 for more information]

Данные для канала 1 OFDM:

Данные для канала 2 OFDM:

Данные для каналов 3 и 4 OFDM:

Результатирующая несущая OFDM:

  CSMA

CSMA	Carrier Sense Media Access
        станция слушает несущюю и передает только когда она свободна
        [Ethernet]

    Станция 1 начала передавать сигнал (т.к. media свободна).

    Станция 2 начала передавать сигнал (т.к. media свободна)

    Возникла коллизия (когда пакеты столкнулись, но ее еще никто не видел).

    Станция 2 увидев коллизию (и передав меньше 32 байтов Ethernet)
    прекратила передачу.

    Станция 1 заметила коллизию

    Теперь они обе будут ждать некоторое случайное время до попытки
    снова передать данные.

ВАЖНО: Минимальная длинна пакета данных должна быть такова что бы в тот момент
       пока пакет еще передается отправителем он достиг границ физической media.
       Это диктует ограничения на длинну сегмента.

Возможны более интересные варианты CSMA:
    циклический опрос
    схемы с маркерами  (TokenRing)


55.3.5. ОСНОВНЫЕ НЕСУЩИЕ СРЕДЫ

THIS SECTION IS UNDER CONSTRUCTION

                    Несущие среды
                      /            \
                Проводные        Безпроводные
                (wire)            (wireless)
                   /       \                 \
          Электрический    Оптоволокно       Эфир
             кабель                 \
       /    |    \                \
    Ленточный   |   Коаксиальный        \
      кабель	|    кабель               \
                |                +---------+--------+
          Витая              |                  |
           пара         Одномодовое        Многомодовое
                        |        |
                        градиентное ступенчатое

  Электрический кабель

Коаксиальный кабель:

Витая пара:

    -----------------------------------
    Category 1	Телефония
    Category 2	IBM  1MHz
    Category 3	16MHz
    Category 4	20MHz
    Category 5	100MHz
    Category 6	250MHz
    Category 7	660MHz  (только STP, причем shield и на кабели и на сигналах)
    -----------------------------------

  Оптоволокно

SMF (Single Mode Fiber)
MMF (Multi  Mode Fiber)

В данном случае Mode - угол отражения луча.

  Эфир

            Эфир
               /    \
        спутниковая  ....
        связь

Спутниковая связь:

Диапазоны частот используемых в спутниковой связи:
    ---------------------------------------------
    Диапазон   Низходящая  GHz  Восходящая
    ---------------------------------------------
    L		1.5		1.6
    S		1.9		2.2
    C		3.7-4.2		5.925-6.425
    Ku		11.7-12.2	14.0-14.5
    Ka		17.7-21.7	27.5-30.5
    ---------------------------------------------

Почему именно такие диапазоны?
Поглощение или отражение  атмосферой в других диапазонах.

GEO:
На GEO спутники нельзя вешать ближе чем 3 угловых градуса друг от друга.
На GEO плохая связь в районах северного и южного полюса.

Большая задержка:
    скорость света ~ 298000 км/сек
    высота GEO     ~ 35838  км
    задержка   = 2 * 35838 / 298000 = 0.24 сек

Для сравнение оптоволокно на 10000 км
    задержка    = 10000 / 298000    = 0.03 сек

Связь в прямой видимости (микроволны)
итд


55.3.5.1. ВОЛНОВОЕ СОПРОТИВЛЕНИЕ КАБЕЛЯ

Кабель можно представить как совокупность сегментов малого размера, каждый
из которых имеет сопротивление индуктивность и емкость:

    R = Ro dz
    L = Lo dz,	где dz - кусочек длинны.
    C = Co dz

Имеем телеграфные уравнения:

    Ro*I + L*dI/dt = - dU/dz
    -dI/dz = Co*dU/dt

Решая их с соответствующими граничными условиями получаем

    Rz = SQRT(Lo/Co)  - волновое сопротивление кабеля.

Что бывает если нагрузка несогласованна с кабелем:

На принимающем конце кабеля:
    Ic*Rz = U
и	In*Rn = U

ток рассоглавования I = Ic - In
по закону сохранения энергии должен куда-то утекать.
Он утекает обратно в кабель в виде отраженной волны.
(В случаях Rn=бесконечность (обрыв) или Rn=0 (короткое замыкание)
происходит полное отражение.

Поэтому очень важно иметь согласованную нагрузку.

Типичные волновые сопротивления:

    Витая пара:	100/120/150 Ом
    Коаксиал:	50/75	    Ом


55.3.5.2. POTS (PLAIN OLD TELEPHONE SERVICES) И DSL

THIS SECTION IS UNDER CONSTRUCTION

  DSL


55.4.1. ПРОБЛЕМЫ СИНХРОНИЗАЦИИ

THIS SECTION IS UNDER CONSTRUCTION

Синхронизация:
    Предположим что тактовая частота передатчика и приемника
    отличаются на 0.1% и изначально они синхронизированны.
    После передаяи 1000 символа синхронизация будет потерена.

При паралельной передаче сигналы приходят не одновременно (перекос сигналов)


55.4.2. ИСКАЖЕНИЕ СИГНАЛОВ: ФИЗИЧЕСКИЕ ОСНОВЫ

THIS SECTION IS UNDER CONSTRUCTION

    При передаче данных сигналы искажаются.

    Затухание - интенсивность сигнала падает с расстоянием
            на разных частотах разное

    Запаздывание - разные частоты распространяются с
            разной скоростью

    Помехи
        Тепловой шум (Thermal Noise)
            N = kTB, где
                B - частота Гц
                T - температура градусов K
                k - константа Больцмана 1.3803*10^-23 Дж/К
            в децибелах:
            N = -228.6 + 10logT + 10logB

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

    Multipath - сигнал может отражатся от объектов и доходит несколькими
            разными путями (соответственно в разное время).

    Эффект Доплера - если передатчик и/или приемник движутся то
             возникает сдвиг частоты (эффект Доплера).

    Shadowing  - внутри зданий падает амплитуда сигнала

    Intersymbol interference

    Размывание по частотам


55.4.3. МОДЕЛЬ КАНАЛА

Вот типичная модель канала.
Считаем что вероятность ошибки при передаче одного символа равна p,
независимо от того идет ли ошибка 0 - > 1, или 1 - > 0.
И что ошибки распределены равномерно и не зависят от предидущих ошибок или
их отсутствия

Тогда вероятность появления строго k ошибки в последовательности
из n символов равна

          n
    (   ) * p^k * (1-p)^(n-k)
      k

Например, пусть вероятность ошибки при передаче одного символа равна p = 0.01

Тогда вероятность что в 8-битовой последовательности будет ровно 1 ошибка
равна:
          8
    (   ) * 0.01 * 0.99^7  ~= 0.07
      1

Вероятность того, что будет ровно 2 ошибки будет равна:

          8
    (   ) * 0.01^2 * 0.99^6 ~= 0.002
      2


55.5. КОДИРОВАНИЕ

Собственно цели у всего кодирования
   Улучшение спектра
    Отсутсвие высокочастотных составляющих (уменьшаем полосу пропускания)
    (пример длинна пита в CD-ROM)
    Вынос основной мощности на середину полосы пропускания (на краях искажения)
   Отсутствие постоянной составляющей сигнала
        (Позволяет делать не прмое соединение, а гальваническую развязку)
   Синхронизация
   Выявление ошибок
   Помехоустойчивость

Кодирование можно условно представить:

    +--------------------+
    |    Data Encoding   |
    +--------------------+
    |   Signal Encoding  |
    +--------------------+

Логическое кодирование (Data Encoding) преобразует поток бит кадра (для сетей)
или сектора (для storage) в последовательность битов для последующего
физического кодирования.

Физическое кодирование (Signal Encoding) преобразует входной поток битов в
физические (электрические,оптические, итд) сигналы

Пример:
    Жесткие диски
        Логическое кодирование: RLL(2,7)
        Физическое кодирование: NRZI

Иногда бывает что и физическое и логическое кодирование совмещают вместе.


55.5.1. ЛОГИЧЕСКОЕ КОДИРОВАНИЕ

  4B5B

4B/5B	- используется в Ethernet 100-Base-FX/TX

Это FDDI: 4B/5B, затем NRZI:

 ------------------------
4B	Char	5B
 ------------------------
0000	0	11110
0001	1	01001
0010	2	10100
0011	3	10101
0100	4	01010
0101	5	01011
0110	6	01110
0111	7	01111
1000	8	10010
1001    9	10011
1010	A	10110
1011	B	10111
1100	C	11010
1101	D	11100
1110	E	11100
1111	F	11101
    Idle	11111
    J	11000
    K	10001
    T	01101
    R	00111
    S	11001
    Quite	00000
    Halt	00100
 ------------------------

8B/10B	- Ethernet 1000-Base-SX/LX/CX
5B/6B   - 100VG-AnyLAN


55.5.2. ФИЗИЧЕСКОЕ КОДИРОВАНИЕ

  NRZ

NRZ (Non Return To Zero Level)

    Недифференциальный
        Если 1 то один уровень (например высокий)
        Если 0 то другой
        используется в RS-232-C (Serial port)
        0 = 0
        1 = 1
    Дифференциальный:
        0 = нет изменений
        1 = в начале интервала меняется состояние

NRZ и NRZI:

  NRZI

NRZI (NRZ Inverted on On Ones)

    инверсен дифференциальному NRZ
    используется в FDDI, Ethernet 100-Base-FX
        0 - нет перехода в начале бита
        1 - есть переход в начале бита
    другой вариант
        Если 1 то в середине интервала переход
        Если 0 то нет перехода.

    Entity nrzi_encoder is
        Port (
            CLK : in std_logic;
            D : in std_logic;
            Q : out std_logic
        );
    End entity nrzi_encoder;

    Architecture basic of nrzi_encoder is
        Signal qint : std_logic := '0';
    Begin
        p1 : process (clk)
        Begin
            If (d = '1') then
                If ( qint = '0' ) then
                    Qint <= '1';
                else
                    Qint <= '0';
                End if;
            End if;
        End process p1;
        Q <= qint;
    End architecture basic;

    Entity nrzi_decoder is
        Port (
            CLK : in std_logic;
            D : in std_logic;
            Q : out std_logic
        );
    End entity nrzi_decoder;

    Architecture basic of nrzi_decoder is
        Signal lastd : std_logic := '0';
    Begin
        p1 : process (clk)
        Begin
            If rising_edge(clk) then
                If (d = lastd) then
                    Q <= '0';
                Else
                    Q <= '1';
                End if;
                Lastd <= d;
            End if;
        End process p1;
    End architecture basic;

  RZ

RZ (Return to Zero)
    Всегда в начале интервала 0V
    Недифференциальный:
              1      0
        +V	 +-+
          0	_	_| |_  _   _
                        | |
        -V              +-+
    Есть и дифференциальный.

RZ (а - обычный, б - дифференциальный)

Пример кодера в RZ код:

Пример декодера из RZ кода:

  AMI

Bipolar AMI
(Bipolar Alternate Mark Invertion)
используется в DS1-DS4,ISDN

    0 = No signal              	0V
    1 = To Positive or negative     Чередуются +V, -V
        (Alternate polariry)

  ASI

ASI (Alternative Space Inversion)
другое имя MAMI (Modified Alternate Mark Inversion)
используется в ISDN
    как AMI, но наоборот
    0 = Чередуются то +V, то -V
    1 = 0V

  HDB3

(High Density BiPolar 3)
It like Bipolar AMI, но в случае 4х нулей подряд
выдается сигнал B00V, где V - выброс в сторону полярности предидущего 1

    ----------------------------------------
    Полярность	Предыдущая замена
    последнего	000+		000-
    импульса        +00+            -00-
    ----------------------------------------
    +		-00-		000+
    -		000-		+00+
    ----------------------------------------

Есть еще HDB2:
    HDB3	0000	в	000V	B00V
    HDB2	000	в	00V	B0V

  B8ZS

B8ZS (Bipolar with 8 Zero Substitution)
    аналогична AMI, но  исключающая последовательности из 8 нулей
    заменяется последовательностью с 2мя нарушениями кодировки

    ----------------------------
    Data	1100000000110000010
    ----------------------------
    AMI 	+-00000000+-00000+0
    HDB3	+-000-+00+-+-00-0+0
          (--)(--)  (--)
    B8ZS    +-000-+0+-+-00000+0
          (------)
    ----------------------------

Есть и другие разновидности:
        B8ZS	00000000   в  000VB0VB
    B6ZS	000000	   в  0VB0VB
    B3ZS	000	   в  B0V  или 00V

B - символ по правилам AMI
V - символ нарушающий правила AMI

B3ZS
    B0V	or	00V
    число импульсов B между двумя последовательными V  нечетно
    полярность V чередовалась

B6ZS
    0VB0VB

B3ZS и B6ZS:

  MLT-3

MLT-3
используется в FDDI, Ethernet 100-Base-TX

    0 = уровень не меняется
    1 = переход к следующему уровню
        +V, 0V, -V, 0V, +V ....

  FM0

FM0 (Frequency Modulation)
    используется в LocalTalk
    На Границе битового интервала состояние меняется на противоположное (+V,-V)

    = 1  не меняется во время битового интервала
    = 0 меняется в середине битового интервала на противоположное

  4B3T

4B3T   (4 Binary to 3 Ternary)
используется в ISDN

 ---------------------------------------------------------------------
    ---- S1 -----   ----- S2 ---    ----- S3 ---    ----- S4 ----
4B	Data	Next	Data	Next	Data	next	Data	Next
 ---------------------------------------------------------------------
0000	+0+	S3	0-0	S1	0-0	S2	0-0	S3
0001	0-+	S1	0-+	S2	0-+	S3	0-+	S4
0010	+-0	S1	+-0	S2	+-0	S3	+-0	S4
0011	00+	S2	00+	S3	00+	S4	--0	S2
0100	-+0	S1	-+0	S1	-+0	S3	-+0	S4
0101	0++	S3	-00	S1	-00	S2	-00	S3
0110	-++	S2	-++	S3	--+	S2	--+	S3
0111	-0+	S1	-0+	S2	-0+	S3	-0+	S4
1000	+00	S2	+00	S3	+00	S4	0--	S2
1001	+-+	S2	+-+	S3	+-+	S4	---	S1
1010	++-	S2	++-	S3	+--	S2	+--	S3
1011	+0-	S1	+0-	S2	+0-	S3	+0-	S4
1100	+++	S4	-+-	S1	-+-	S2	-+-	S3
1101	0+0	S2	0+0	S3	0+0	S4	-0-	S2
1111	++0	S3	00-	S1	00-	S1	00-	S3
 ---------------------------------------------------------------------

  8B6T

8B6T	(8 Binary to 6 Ternary)
используется в Ethernet 100-Base-T4
    00h	+-00+-
    01h	0+-+-0
    .....
    FEh	-+0+00
    FFh	+0-+00

  2B1Q

2B1Q (2 binary to 1 quaternary)
используется в ISDN.

    00	-2.5V
    01	-0.883V
    10	+2.5V
    11	+0.883V

  PAM4

PAM4 (Pulse Amplitude Modulation 4)

    11	+Vs
    10	+2Vs/3
    01	+Vs/3
    00	0

PAM5 кодирование
как PAM4, но биполярное и отсутствие сигнала означает управляющий символ

  PPM

PPM (Pulse Position Modulation)
Сигнал находится в определенной позиции

  PFM

PFM (Pulse Frequence Modulation)
Количество импульсов в определенный промежуток времени

  PWM

PWM (Pulse Width Modulation)
Разная длинна импульса

  Код Миллара

    =1 Сигнал меняется в середине интервала
    =0 Сигнал не меняется

    Если два нуля идут подряд между ними сигнал меняется в
    середине интервала.

  Манчестер-II

Манчестер-II используестся в 10MB Ethernet
    Манчестер-II (Ethernet)
    плюс кодирования - обнаружение коллизий
        0 - низкий в высокий в середине бита
        1 - высокий в низкий в середине бита

    Дифференциальная манчестерская
        в середине интервала всегда переход
        0 - переход в начале интервала
        1 - нет перехода в начале интервала

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

Пример кодировщика в Манчестер-II:

    Library ieee;
    Use ieee.std_logic_1664.all;
    Entity Manchester_encoder is
        Port (
            Clk : in std_logic;
            D : in std_logic;
            Q : out std_logic
        );
    End entity Manchester_encoder;

    Architecture basic of Manchester_encoder is
        Signal lastd : std_logic := '0';
    Begin
        P1: Process ( clk )
        Begin
            If rising_edge(clk) then
                if ( d = '0' ) then
                    Q <= '1';
                    Lastd <= '0';
                elsif ( d = '1' ) then
                    Q <= '0';
                    Lastd <= '1';
                Else
                    Q <= 'X';
                    Lastd <= 'X';
                End if;
            End if;
            If falling_edge(clk) then
                If ( lastd = '0' ) then
                    Q <= '0';
                elsif ( lastd = '1' ) then
                    Q <= '1';
                Else
                    Q <= 'X';
                End if
            End if;
        End process p1;
    End architecture basic;

    Entity Manchester_decoder is
        Port (
            Clk : in std_logic;
            D : in std_logic;
            Q : out std_logic
        );
    End entity Manchester_decoder;

    Architecture basic of Manchester_decoder is
        Signal lastd : std_logic := '0';
    Begin
        P1 : process (clk)
        Begin
            If rising_edge(clk) then
                Lastd <= d;
            End if;
            If falling_edge(clk) then
                If (lastd = '0') and (d = '1') then
                    Q <= '1';
                Elsif (lastd = '1') and (d = '0') then
                    Q <= '0';
                Else
                    Q <= 'X';
                End if;
            End if;
        End process p1;
    End architecture basic;

  Спектральные характеристики


55.5.3. КАДРЫ

Как правило данные передаются кадрами (Frame).
Типичный кадр имеет формат:

    +---------+
    |Preambule|	Используются для синхронизации начала кадра
    |	  |	на media или в сети
    +---------+
    | Address |	Адресс получателя (и отправителя) (в сети)
    |	  |	иногда адресс сектора на media
    |	  |	[может и отсутсвовать если Point-to-Point,
    |	  |	или media hard-sectored или серворазметка]
    +---------+
    |         |
    |  Data   |	Блок данных
    |	  |
    +---------+
    |  FCS    |	Frame Checksum
    |	  |	Контрольные или Корректирующие ошибку коды
    +---------+
    |Terminate|	Коды указывающие на конец кадра
    |	  |	[могут отсутствовать]
    +---------+

  RS-232-C

Рассмотрим формат кадра последовательного порта (RS-232-C):

Мы видем:
    +----------+
    |Start Bit |	Стартовый бит - preambule.
    +----------+
    |          |
    =   Data   =	Биты данных
    |	   |
    +----------+
    |Parity Bit|	Бит четности данных - контроль ошибок
    +----------+
    |StopBit(s)|	Стоповый бит - указывает на конец кадра
    +----------+

  Ethernet

Другой типичный пример - это кадры Ethernet.

         00    01    02    03    04    05    06    07
      +-----+-----+-----+-----+-----+-----+-----+-----+
+0000 |                   Preambule                   |
      +-----+-----+-----+-----+-----+-----+-----+-----+
+0008 |        Destination Address        |
      +-----+-----+-----+-----+-----+-----+
+000e |          Source Address           |
      +-----+-----+-----+-----+-----+-----+-----+-----+
+0014 |                                               |
      =			  Data			      =	 62-1502 bytes
      |                                               |
      +-----+-----+-----+-----+-----+-----+-----+-----+
+END-4|          CRC          |
      +-----+-----+-----+-----+

Мы видим все тоже самое:
    Синхропоследовательность, Адрес, Данные, Контрольная сумма.
    (Кодов указывающих на конец кадра нет - просто media будет
    не модулированна после посылки).

  CD-ROM  frame

CD-ROM frame - это 588 битов (CD-ROM сектор = 98 CD-ROM frames).

Имеет формат:

Количество
битов	  +----------+
24+3	  |	     |  Synchropattern  = 100000000001000000000010
      |	     |
      +----------+
14+3	  |	     |  Subchannel - это адрессная и другая информация
      |	     |		     типа CD-Text (1 байт)
      +----------+
24*(14+3) |	     |  Data (24 байта)
      +----------+
8*(14+3)  |	     |  CIRC - Коды Рида-Соломона для исправления ошибок
      +----------+  8 байт

Subchannel,Data и CIRC - кодируется по ЕFM (отсюда 14).
Synchropattern   - не кодируется по EFM - он уже такой.
К каждому 14бит EFM и к Synchropattern добавляются дополнительные 3
бита для того что бы код имел нужный спектр.

  Floppy disk

Формат сектора Floppy диска:

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

+-------+
| 50x4E	|	Gap  перед адрессом сектора
+-------+
| 12x00 |	Sync
+-------+
| 3xA1  |	Указание на данные адресса сектора (Маркер адресса сектора)
|   FE  |
+-------+
| CYL   |	Номер цилиндра
+-------+
|  HD   |	Номер головки
+-------+
|  SEC  |	Номер сектора
+-------+
|  NO   |	Размер сектора  (на Floppy от 256 байт до 1KB).
+-------+
|  CRC  |	CRC для адресса сектора
+-------+
| 22x4E |	Gap    (Нужен чтобы котроллер дискеты успел)
+-------+                                      		--+
| 12x00 |	Sync                                      |
+-------+                                                 | Это пишется
| 3xA1  |	Указание на данные (Маркер данных)        | при записи
| FB/F8 |                                                 | сектора
+-------+                                                 |
| DATA  |	Данные                                    |
+-------+                                                 |
| CRC   |	CRC данных                                |
+-------+                                               --+
|       |
| GAP   |	Большой межсекторный Gap
|       |
+-------+

Данные FM или MFM модулированны.


55.6. МОДУЛЯЦИЯ

THIS SECTION IS UNDER CONSTRUCTION

Несущая частота (Carrier)

Руки в масле, ноги в мыле,
Мы тут carrier ловили.

Скорость передачи данных = бит/сек  (bps)
Скорость модуляции - частота изменения сигнала в секунду - бод (baud)

            Цифровая модуляция
            /   		\
        с постоянным          с непостоянным
        конвертом              конвертом
         (constant envelope)      (nonconstant envelope)
           /       |          \           |     |
         FSK      PSK         CPM        ASK    QAM
       /   \       |             \
     BFSK  MFSK    |               \
      |            |                 \
           BPSK ---+---- MPSK       SHPM
      |            |                /  \
          QPSK           GMSK  LREC
         /    \                 |
      |        OQPSK  PI/4-QPSK         CPFSK
                |                         |
      |         + - - - - - - - - - - \   |
      + - - - - - - - - - - - - - - - -  MSK

  Типы модуляции:

  Амплитудная модуляция

    Амплитудная
    ASK (Amplitude-shift keying)
        s(t) =  | A cos(2 * PI * Fc * t)	if 1
            | 0				if 0
        B    = (1 + r) * R

Пример ASK:

  Частотная модуляция

    Частотная
    FSK (Frequency-shift keying)
        s(t) =  | A cos(2 * PI * (Fc - m) * t)	if 1
            | A cos(2 * PI * (Fc + m) * t)  if 0
        если бит в боде > 1, то используется большее число частот
        [MFSK (MultiFrequency-shift keying)
        B    = 2 * M + (1 + r) * R

Пример FSK:

Пример 4FSK (используются 4 частоты):

  Фазовая модуляция

    Фазовая (PSK - Phase-shift keying)
    BPSK (Binary Phase-shift keying)
    используются 2 фазы (поэтому Binary) [амплитуда всего одна]
    кодируется 1 бит
        s(t) = |   A cos(2 * PI * Fc * t)	if 1
               | - A cos(2 * PI * Fc * t)	if 0
Пример PSK:

Квадратурная диаграмма для BPSK:

Eye Diagram для BPSK (теоретическая):

Eye Diagram для BPSK (реальная):

Пример несущей для BPSK:

Реально мерить абсолютную фазу неудобно, поэтому часто мерят только сдвиг фазы
DPSK (Differentica PSK)

    0 = фаза не меняется
    1 = фаза меняется

    QPSK (Quadrature phase-shift keying)
    используются 4 фазы (поэтому Quadrature) [амплитуда всего одна]
    кодируется 2 бита

    Оригинальная QPSK:
        s(t) =  |  A cos(2 * PI * Fc * t)	   if 11
            |  A cos(2 * PI * Fc * t + PI/2)   if 10
            |  A cos(2 * PI * Fc * t + PI)     if 00
            |  A cos(2 * PI * Fc * t + 3PI/2)  if 01

Квадратурная диаграмма для QPSK:

Квадратурная диаграмма с посылаемыми сигналами:

Реальная квадратурная диаграмма при приеме:

QI данные при передаче:

Несущая QPSK для данных выше:

Типы QPSK:

PI/4-DQPSK:
(фаза меняется всегда, но никогда на 180 градусов):

    OQPSK (Offset QPSK)
    используются четыре фазы [амплитуда всего одна]
    Сдвиг фазы возможен только на PI/2.
    Потому что биты в I и Q изменяются не одновременно,
    а со сдвигом T/2 относительно друг друга

Сравнение QPSK и OQPSK:

Сравнение несущих QPSK и OQPSK:

    8PSK (8 phase-shift keying)
    используется 8 фаз [амплитуда всего одна]
    кодируется 3 бита

Квадратурная диаграмма для 8PSK:

QI данные при передаче 8PSK:

Несущая для 8PSK:

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

Сравнение разных модуляций на 16 точек (смотрите плотность):

        B = [ (1+r) / L) ] * R

    B - ширина полосы пропускания
    R - скорость передачи данных (бит/сек)
    L - число битов в сигнальной посылке
    r - коэффициент связанный с фильтрацией стгнала (0 < r < 1)

        D = R / L

  MSK

THIS SECTION IS UNDER CONSTRUCTION

MSK (Minimal Shift Keying)

QI данные при MSK модуляции:

Несущая в MSK модуляции:

Сравнение спектра MSK и FSK:

  GMSK

GMSK (Gaussian Minimal Shift Keying)
в PSK происходит резкий скачок фазы - это плохо если у нас малая полоса
пропускания (как в GSM).

Используются не синусоиды, а пики Гаусса.

Поэтому в GMSK фаза меняется не скачком, а плавно в течении всего
периода действия 0 или 1.

QI данные в GMSK модуляции:

Несущая в GMSK модуляции:

  Модуляция со скачком частоты

    Со скачком частоты
    MFSK  (Multi-Frequency shift keying)
        s(t) = A cos(2 * PI * Fi(t) * t)
            Fi - соответствующая частота на которой идет
                 передача в соответсвующий момент времени.

  QAM

    QAM (Quadrature-Amplitude Modulation)

Основа QAM модуляций:
    Мы передаем сигнал как вектор
    (амплитуда и смещение фазы относительно несущей)

QAM8 модуляция:

Сигнальная звезда QAM8:

Пример несущей QAM8:

QAM16 модуляция:

Пример квадратурной диаграммы для QAM16:

Квадратурная диаграмма для QAM16 c величинами амплитуд:

Как QAM16 реализуется:
(сумма двух QPSK c разными амплитудами)

Сравнение QAM16 и QPSK:

QAM32
Квадратурная диаграмма для QAM32:

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

  Trellis кодирование

Trellis кодирование (TCM) - решетчатое кодирование.

Когда у нас большой QAM то точки в пространстве состояний становятся ближе
друг к другу (вероятность ошибки выше).

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

Для реализации этой избыточности аппаратно вводят схемы свертки.
Результат свертки зависит от текущих и предидущих данных.
Пример свертки 2 бита в 3:

Дистанция для TCM:

Кодер для TCM:

Решетка Витерби:

Рассмотрим для примера V.32 на 9600 бит/сек.

V.32 сигнальная звезда (квадратурная диаграмма):

Таблица для разностного кодирования (свертки) V.32:
 ------------------------------------------
Вход		Выходные биты
Информация	Предыдущие	Новые
 ------------------------------------------
00		00		00
00		01		01
00		10		10
00		11		11
01		00		01
01		01		00
01		10		11
01		11		10
10		00		10
10		01		11
10		10		01
10		11		00
11		00		11
11		01		10
11		10		00
11		11		01
 ------------------------------------------

Схема свертки для V.32 9600:

Кодер для V.32 9600:

Координаты сигнальных точек V.32 9600bps:
 -------------------------------
Y0Y1Y2Q3Q4	Real	Im
 -------------------------------
00000		-4 	1
00001           0       -3
00010           0       1
00011           4       1
00100           4       -1
00101           0       3
00110           0       -1
00111           -4      -1
01000           -2      3
01001           -2      -1
01010           2       3
01011           2       -1
01100           2       -3
01101           2       1
01110           -2      -3
01111           -2      1
10000           -3      -2
10001           1       -2
10010           -3      2
10011           1       2
10100           3       2
10101           -1      2
10110           1       -2
10111           -3      -2
11000           1       4
11001           -3      0
11010           1       0
11011           1       -4
11100           -1      -4
11101           3       0
11110          -1       0
11111          -1       4
 -------------------------------

Сигнальная звезда V.32:

Различные звезды модуляции:

  Характеристики

SNR для модуляций:

Влияние кодирования на TCM:

В реальных модемах используются разные модуляции на разных частотах
Это связано с тем что у концов полосы пропускания падает SNR.


55.6.1. РЕАЛИЗАЦИЯ МОДУЛЯТОРОВ И ДЕТЕКТОРОВ

  Амплитудный модулятор

Амплитудный модулятор:

Схема для эмуляции амплитудного модулятора:

  BPSK модулятор

Основу BPSK модулятора составляет схема расщепление фазы:

Схема для расшепления фазы:

  PSK и QAM модуляторы

Как добится амплитудной модуляции?
     (смотри выше амплитудный модулятор).
Как добится фазовой модуляции?
     на 180 градусов (смотри схему расщепления фазы выше).
     на другой угол (можно использовать R-C цепочки)

QAM модулятор:

QAM детектор:

QAM4 кодер:

QAM4 декодер:

QAM16 кодер:


55.7. ПЕРЕДАЧА АНАЛОГОВЫХ ДАННЫХ ПО ЦИФРОВЫМ КАНАЛАМ

THIS SECTION IS UNDER CONSTRUCTION

Чтобы передать аналоговые данные по цифровым каналам - надо их
оцифровать.

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

Частота дискретизации - количество выборок в единицу времени.

Теорема Найквеста:
    Если из сигнала через постоянные промежутки времени осуществляются
выборки, причем Fsam > 2 Fsig (где Fsam = частота выборки [1/ceк],
Fsignal - максимальная частота сигнала), то выборка содержит всю
информацию о сигнале.

Пример выборки для которой Fsam < 2 Fsig:

Мы видим, что в результате появился побочный сигнал.

  PCM

PCM (Pulse-Code-Modulation)
Выборка представляет собой число N, которое имеет размер log2(состояний_АЦП) бит.

        PCM кодирование
        /        \
     линейное       нелинейное

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

        PCM кодирование
        /        \
        простое	диффиренциальное (DPCM)

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

TODO: Еще есть ADPCM

Нелинейное PCM кодирование

Линейный PCM:

Нелинейный PCM:

Поскольку чуствительность человеческого уха логарифмическая,
то сжатие означает больше отчетов на маленькие сигналы.

Субъективное сжатие:

Логарифмическое - используется в PSTN (Public Switched Telephone Network)

m-Law:
    используется в США и Японии

    s  - значение линейного PCM
    sm - значение m-Law PCM
    sm = sign(s) * log(1 + 255 * |s|) / log(1+255)

A-Law:
    используется в Европе

    s  - значение линейного PCM
    sa - значение m-Law PCM
    sa =  A / (1 + ln(A)) * S,		если S =< 1/A
          (1 + ln(A * s) / (1 + ln(A)),	если 1/A =< |s| =< 1

  Дельта-модуляция

DM (Delta-Modulation)
Дельта-модуляция - один бит на выборку:
        = 1 - усилить сигнал
        = 0 - ослабить сигнал
    (в принципе бывают варианты с более чем 1 бит на выборку).

Дельта-модуляция:

Недостатки Дельта-модуляции:
    Возможна перегрузка (не успеваем за сигналом).
    Если сигнал постоянен, происходит шум +-+-+-+-


55.8. ПЕРЕДАЧА АНАЛОГОВЫХ ДАННЫХ ПО АНАЛОГОВЫМ КАНАЛАМ

THIS SECTION IS UNDER CONSTRUCTION

AM,FM,PM

AM
    Длинные волны

PM

FM

Для аналогово сигнала FM и PM - одно и то же.

FM-радио наверное слушали все
Стерео сигнал просто на соседних частотах

Пример амплитудной модуляции:

Пример амплитудной модуляции видеосигнала:


55.9. СЕТИ

THIS SECTION IS UNDER CONSTRUCTION

          Сети
           /  |  \
        LAN  MAN  WAN

LAN (Local Area Network)
MAN (Metropolitan Area Network)
WAN (World Area Network)

В настоящее время различие между MAN и WAN стирается.

  ISO модель

Семиуровневая ISO модель:

       ISO	OSI
    +--------------+
    | Application  |
    +--------------+
    | Presentation |
    +--------------+
    | Session      |
    +--------------+
    | Transport    |
    +--------------+
    | Network      |
    +--------------+
    | Channel      |
    +--------------+
    | Physical     |
    +--------------+

Передача данных по сети:

      Отправитель					   Получатель
    +--------------+ 				+--------------+
     |	| Application  |    				| Application  |   ^
     |	+--------------+    				+--------------+   |
     |	| Presentation |     				| Presentation |   |
     |	+--------------+    				+--------------+   |
     |	| Session      |            Узлы            	| Session      |   |
     |	+--------------+    	    сети		+--------------+   |
     |	| Transport    |    	 (Маршрутизаторы)	| Transport    |   |
     |	+--------------+    	+--------------+  	+--------------+   |
     |	| Network      |    +-->| Network      |--+  	| Network      |   |
     |	+--------------+    |	+--------------+  | 	+--------------+   |
     |	| Channel      |    |	| Channel      |  | 	| Channel      |   |
     |	+--------------+    |	+--------------+  | 	+--------------+   |
     |	| Physical     |    |	| Physical     |  | 	| Physical     |   |
     V	+--------------+    |	+--------------+  |	+--------------+   |
      --------------------->|                     V  --------------------> |

  Сетевые устройства

Разные сетевые устройства работают на разном уровне.

Пассивный хаб [Repeater/Hub] (электрически повторяет сигналы)     Physical

Repeater - 2-портовый

Hub      - многопортовый

Активный хаб  [Switch/Hub] (маршрутизирует по MAC адрессам)       Channel

Bridge	- 2-портовый интелектуальный Repeater

Switch  - многопортовый Bridge

Маршрутизатор [Router] (маршрутизирует по сетевым адрессам)       Network

Gateway - 2-портовый маршрутизатор

Router  - Многопортовый маршрутизатор

Характеристики линии


55.9.1. ПОВТОРЕНИЕ ПЕРЕДАЧИ

Задачи:
    Передать без ошибок
        FEC (Forward Error Control)
        ARQ (Automatic Repetition Query)
            с остановкой и ожиданием
            с возвратом N кадров
            с избирательным повторением

ARQ (Automatic Repetition Query)
     Запрос на автоматическое повторение

  SAW

SAW (Stop and Wait)
с остановкой и ожиданием

  GBN

GBN (Go Back N)
с возвратом N кадров

  SR

SR (Selective Repeat)
с избирательным повторением

  Эффективность


55.9.2. ТИПЫ СЕТЕЙ

          Сеть
        /     \

Connection-oriented  Conectionless

  Топология сети

  Фрагментация

Сетевые технологии развиваются гораздо быстрее чем вычислительная мощность.
Рассмотрим крупную корпорацию:
Подсчитаем:
1980 год - имеем модемы на 2400 бод
       8086 - 5MHz (1 команда за 4 такта)
2006 год - 10G Ethernet
       CPU - > 3GHz, Dual core (5 комманд за такт)
                 (если надо обращаться к памяти то медленнее)

-----------------------
год	Net	CPU
-----------------------
1980	2.4K	1.25M
2006	10G	15G
-----------------------
рост	~10M	~10K
-----------------------

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

Эта тенденция уже наблюдается в сетевых протоколах.

Например если IPv4 пакет (обычный без DF флага) дойдет до router у которого
MTU меньше чем размер пакета, то router его фрагментирует.

Но уже в IPv6 в этом случае router сбросит пакет, и пришлет сообщение
что надо использовать MTU меньшего размера.

В принципе сейчас технология с минимальным MTU - это X.25,
у нее MTU = 576 байт.


55.9.3. СЕТЕВЫЕ СЕРВИСЫ

Для работы сети нужны сетевые сервисы:


55.9.3.1. РАЗРЕШЕНИЕ АДРЕССОВ В ЛОКАЛЬНОМ СЕГМЕНТЕ СЕТИ

  Connectionless Network

Компьютер знает свой MAC адресс, но он не знает кто в физической сети
на Level 2, обладает каким сетевым адрессом.

Что бы это решить используются протоколы разрешения адресса.

Для IPv4 это ARP (Address Resolution Protocol)

Информация о разрешенных адрессах храниться в ARP Table:

  Connection-oriented Network

На примере ATM.
Компьютер не знает кто в физической сети обладает каким сетевым адрессом.
Но у компьютера есть постоянное виртуальное соединение (PVC - Permanent Virtual
connection) [задается администратором сети на компьютере и на ATM-коммутаторе]
с сервером LANE (LAN Emulation) который отслеживает все соответствия физических
и логических адрессов (Каждый компьютер при старте сообщает серверу LANE эту
информацию).
Сервер LANE возвращает адресс target компьютера, после чего исходный компьютер
устанавливает с ним соединение.


55.9.1.2. СЛУЖБЫ ИМЕН

THIS SECTION IS UNDER CONSTRUCTION

Адресса сетевого уровня неудобны для запоминания человеком.
Например мой сайт имеет IP адресс 212.204.221.91, но запомнить я это не
могу, поэтому используют человеческие имена, например phg.chiplist.com

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

Пример: DNS протокол в IPv4

Root DNS сервера:

-------------------------------------------------------------------------
; formerly NS.INTERNIC.NET
;
.                        3600000  IN  NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
;
; formerly NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     128.9.0.107
;
; formerly C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
;
; formerly TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     128.8.10.90
;
; formerly NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
;
; formerly NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
;
; formerly NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
;
; formerly AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     128.63.2.53
;
; formerly NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
;
; temporarily housed at NSI (InterNIC)
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     198.41.0.10
;
; housed in LINX, operated by RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
;
; temporarily housed at ISI (IANA)
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     198.32.64.12
;
; housed in Japan, operated by WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
-------------------------------------------------------------------------

Информация о разрешенных адрессах храниться в DNS Cache:


55.9.3.2. ТИПЫ АДРЕССОВ

THIS SECTION IS UNDER CONSTRUCTION

Каждый пакет (или канал) имеет свой адресс назначения.

    Адресса
        Уникальные
            Unicast
        Групповые
            Broadcast	всем в данном сегменте LAN
            Multicast	всем входящим в группу
            Anycast		ближайшему входящему в группу

Причем это деление есть как в MAC адрессах, так и в сетевых
(за исключением того что anycast есть только в сетевых)

  MAC адресса

  Сетевые адресса


55.9.3.4. МАРШРУТИЗАЦИЯ

THIS SECTION IS UNDER CONSTRUCTION

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

Маршрутизация:
        Маршрутизация
        /         \
       Статическая	 Динамическая

    Статическая  - заранее перманентно известно куда послать
               минусы: если канал умер, то мы тоже
    Динамическая - строим маршрут на основании маршрутной информации

        Маршрутизация
        /         \
     одномаршрутная	 многомаршрутная

Одномаршрутная  - router имеет один маршрут по которому и шлет
Многомаршрутная - router имеет несколько маршрутов (может отсылать по ним)

        Маршрутизация
        /         \
    одноуровневая	 иерархическая

Одноуровневая - вся сеть равноценна
Иерархическая - есть специальные области (как правило backbone)
        или интернет есть AS (они обмениваются информацией по inter-AS
        протоколам (например BGP))

Пример иерархической сети для OSPF:

        Маршрутизация
        /         \
      внутридоменная  междоменная

Внутридоменная - RIP, OSPF, IGRP
Междоменная    - BGP

        Маршрутизация
        /         \
       глобальная    децентрализованная
    (рутеры знают	 (рутеры знают только
        топологию сети)        соседей)
      "Link State"      "Distance Vector"
               "Path Vector" (BGP, extension of Distance Vector)

       Алгоритм Декстры

       Лавинная маршрутизация

       Распределенная маршрутизация
        по вектору расстояния (RIP)
        [Distant Vector]
            Split Horazon
            Poisoned Reverse

        по состоянию связи    (OSPF)
        [Link State]

            итд.
        протоколы досягаемости (BGP)
    Multipath Routing

    Маршрутизация от источника

  Метрика

Метрика - абстрактный способ измерения степени близости между двумя
объектами.

Критерии для Routing metric

    Длинна пути (количество хопов)
    Reliability (bit-error rate)
    Пропускная способность линии
    Задержка на линии
    Загрузка (CPU Utilization)
    Стоимость

  Flooding

  Count to infinity

Как только значение метрики достигнет определенной величины считаем
что оно бесконечное (то есть сеть недостижима).

  Split Horizon

Не пересылаем информацию о достижимости сети тем соседям от которых мы получали
информацию о достижимости этой сети (пусть даже по разным маршрутам).

  Poisoned Reverse

Тому от кого мы получили информацию о достижимости сети посылаем что эта сеть
недостижима.

  Triggered Update

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

  Load Balancing

  Внутренняя маршрутизация

Пусть у нас есть сеть:

Покажем принципы как происходит сбор маршрутной информации.
Каждый маршрутизатор шлет соседним ниформацию о сетях которые через
него достижимы.
Шаг 1:

Шаг 2: К этой информации добавляется новая полученная на шаге 1.
И процесс повторяется.
Алгоритмы маршрутизации отслеживают петли, уменьшают количество информации
не посылая информацию о сетях полученных через маршрутизатор от которого ее
получили, ограничивают число шагов.

Если есть петли то возникают множественные маршруты.
Тогда начинают применять дополнительные аттрибуты для того чтобы выбрать
лучший путь:
например число пройденных маршрутизаторов.
(Это не всегда оптимально: пример:
    1 маршрутизатор через модем
    3 маршрутизатора, но все сети Gigabit Ethernet).
Поэтому этим критерием сейчас практически на пользуются.

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

Примеры таблицы маршрутизации:

Конфигурация:

  Проблемы

Overloading

Link Failure

  Внешняя маршрутизация

Основа внешней маршрутизации - AS (Автономные системы).
Через AS траффик не проходит - она является конечной точкой получения/
отправления пакетов.
AS обмениваются друг с другом информацией о достижимости.

Типы AS:
    Stub AS
    Multihomed AS
    Transit AS

Stub AS:

Multihomed AS:

Transit AS:

  Иерархия Inet

  MPLS

MPLS (Multiprotocol Label Switching)

Для минимизации вычислительных затрат при входе в транзитную (необ) зону по
сетевому адрессу назначения пограничным маршрутизатором (Edge Router)
формируется и добавляется к датаграмме метка которую используют для
быстрой маршрутизации во внутренней сети (Core Routers).


55.9.4. КАК РАБОТАЕТ МАРШРУТИЗАТОР ROUTER

THIS SECTION IS UNDER CONSTRUCTION


55.9.5. КАК РАБОТАЕТ КОММУТАТОР (SWITCH)

  Обучение

  Flood

  Spanned Tree

Чтобы предотвратить flooding L2 switches обмениваются информацией по BPDU
протоколу и строют spanned-tree.
(В случае когда несколько коммутаторов могут быть корнем для spanned-tree
выбирается тот у кого MAC адресс меньше).


55.10. ХРАНЕНИЕ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

          Хранение  данных         --------+
    /       |          \                |
  магнитные    магнитно    оптические     прочие носители.
  носители     оптические  носители
               носители

        Storage
        /     \
      Прямого     Последовательного
      доступа     доступа
      (диски)     (ленты)

Архитектура хранения данных

THIS SECTION IS UNDER CONSTRUCTION

Задачи:
    увеличение производительности
        увеличение плотности записи
            совершенствование аппаратной базы
                создание материалов с лучшеми свойствами
        ZBR (Zoned Bit Recording)
        Увеличение частоты вращения диска/скорости ленты
        Interleave (актуален и сейчас как сдвиг начала трека
                на соседнем цилиндре)
        Кэширование (caching)
        Предчтение (prefetching)
        Request Reordering (неупорядоченное выполнение запросов
        Banking (расслоение по нескольким устройствам)
            [см. следующий topic]
        Write Back и правильно организованные файловые системы
    увеличение надежности
        Коды корректирующие ошибки
        Замена дефектных секторов

  Увеличение плотности записи

    Увеличение плотности записи в 2 раза (например с 15 бит на см^2
    до 30 бит на см^2) при той же линейной скорости увеличивает
    линейную плотность данных в SQRT(2) = 1.41 раза
    Но за это надо платить улучшением аппаратной базы:
    Использовать материалы с лучшими свойствами
    Делать более сложные головки записи.

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

  Увеличение частоты вращения диска

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

  ZBR (Zoned Bit Recording)

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

Пример обычного диска и диска с двумя зонами:

Пример мультизонного диска:

    Соответственно во внешних областях диск работает быстрее
    (поэтому начало диска идет во внешних зонах).

  Паралельные головки

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

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

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

Есть вариант с двумя блоками головок.

  Interleave

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

  Track/Cylinder Skew

    Современные диски имеют cache и читают весь track целиком,
    поэтому для них Interleave не актуален.
    Но тем не менее существует сдвиг начала следующего трека по
    отношению к текущему (это позволяет быстрее читать последовательные
    данные).  (Track skew, Cylinder skew)
Поверхность 1:

Поверхность 2:

  Elastic BPI

    В современных дисках используется elastic BPI.
    Т.е. плотность записи подбирается индивидуально для каждой
    пластины в зависимости от ее физических характеристик.

  Average Seek Time

    Average Seek Time = среднее время позиционирования головки по диску
                + 1/2 * время оборота диска.

У современных дисков чисто seek занимает меньше 1 ms.

  Кэширование и предчтение

    В cache держат данные и читают не секторами а сразу треками
    Это позволяет быстрее обратится к уже прочитанным или
    последовательным данным.

  Неупорядоченное выполнение

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

    Запросы диск может выполнять последовательно
    (FCFS - First Come First Service)

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

    Но диск может быть умным (SCSI) и выполнять запросы так что бы
    минимизировать перемещения головки
    (Это поднимает производительность).

    Перемещаем головку так, что бы двигать ее как можно меньше
    т.е. ближайшему запросу (Minimum Seek):
    (SSTF - Shortest Seek First)
Minimal seek:

    Один из механизмов - это Elevator (лифт).
    Идем до самого младшего запрашиваемого блока (всех обслуживаем по пути),
    потом до самого старшего, итд.
Elevator:

    Есть разновидности Elevatora:

C-SCAN: Всегда доходит до последнего цилиндра,
затем быстрый seek на первый цилиндр (ничего не читая по дороге):

C-LOOK: Всегда доходит до верхнего запроса, затем быстрый seek
на самый младший запрос (ничего ни читая по дороге)

Вся эта механика может быть реализована внутри диска (SCSI) или
реализовыватся внутри OS.
Но понятное дело диск лучше знает свою зонную структуру и времена для
выполнения операций).
Именно по этому (на самом деле есть еще причины) SCSI диски более
дорогие чем IDE.

Трансляция внутренних структур диска во внешние LBA/CHS - личное дело самого
диска.

  Увеличение надежности

  Замена дефектных секторов

    (Spare sectoring, Defects Mapping)
    Дефекты поверхности диска встречаются часто
    (и появляются тоже - например ударили компьютер - головка цепанула
    поверхность).

    Раньше на диске была наклеена карта defect blocks.
    Почему на современных дисках нет ни одного bad blockа?
    Они заменяются.

    После записи диск проверяет записался ли сектор, если нет то
    тестирует сектор, если сектор плохой то помечает его как плохой,
    а данные пишет вместо него в зарезервированный сектор.

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

HSM

Data Tiering


55.10.0. RAID

RAID - Redundant Array of independed disks

  JBOD

JBOD (Just bunch of disks)

  RAID-0

RAID-0  Stripe Set

  RAID-1

RAID-1  Mirror

  RAID-1E

  RAID-2

RAID-2 Hamming code ECC  (7,4)
SECDEC

  RAID-3/RAID-4

RAID-3 and RAID-4
Stripe set with Parity
Разница в том, что RAID-3 parity побайтно, а RAID-4 поблочно.

RAID-4:

  RAID-5

RAID-5
Stripe set w/Rotated Parity
Parity распределена по всем дискам - поэтому работает быстрее чем RAID-3
1 колонка parity

{a,b,P}
    a + b = P
    (a,b)	a, b
    (b,P)	a = P - b
    (a,p)	b = P - a

RAID-5 имеет два основных варианта
    Правовращающееся parity
    Левовращающееся симметричное (более быстрый)

Отказ одного диска:

Отказ двух дисков:

  RAID-5 with spare

  RAID-5E

  RAID-5EE

  Другие варианты расширенного RAID-5

  RAID-6

RAID-6
Stripe set w/Rotated Parity
2 колонки parity

{a,b,P,Q}
    a + b = P
    log{a} + log{b} = Q

    для Q обычно берут GF(2^8)
    log{x} дискретный имеет для 1..FF значения показателя степени
    образующего полинома 0..FE
    для 00 считают что степень будет бесконечностью и представляют ее
    как FF.

    Что происходит ели вылетит 2 диска:
    (a,b)	a,b
    (a,P)	b = P - a
    (b,P)   a = P - b
    (a,Q)	b = antilog(Q - log{a})
    (b,Q)   q = antilog(Q - log{b})

{a,b,c,P,Q}
    если вылетели диски с четностью - то нормально
    если вылетел диск с четностью и данными - то смотри выше
    вылетело 2 диска с данными
    (a,P,Q)
    имеем систему уравнений:
    | b + c = P - a
    | log{b} + log{c} = Q - log{a}
    решая ее получаем a и b

    один из вариантов решения просто подбором по b (всего 256 вариантов
    в среднем 128) в пересчете на байт.

    TP = P ^ a;			// XOR
    TQ = Q - log{a}
    b = 0;
    while (b < 256)
    {
        c = TP ^ b;		// XOR
        lb = log_table[b];
        lc = log_table[c];
        if ((lb + lc) == TQ))
        {
            return	b,c;
        }
        b++;
    }
    естественно имеем в памяти таблицу дискретных алгоритмов.
    порядка 7 операций на итерацию
    на востановление байта: 7-1792 операций в среднем 896
    на сектор (512 байт): 3584-917504 операций
    получается на современном процессорном ядре можно востановить в
    худшем случае порядка 1-2К секторов в секунду
    то есть порядка 1MB.
    Неудивительно что используют специальные контроллеры.

  RAID-6E

Аналогично как RAID-5E

  RAID-10

RAID-10:

  RAID0+1

  RAID_30

RAID-30:

  RAID-50

RAID-50:

  RAID-51

  RAID-60

  RAID-61

  RAID-DP

Повышается надежность:

Software и Hardware

Hardware:

Software:


55.10.1. МАГНИТНЫЕ НОСИТЕЛИ

THIS SECTION IS UNDER CONSTRUCTION

  Жесткие диски и дискеты

  Физические основы

при движении проводника в магнитном поле возникает ток:

    магнитные домены
    сильным магнитным полем перемагничиваем

    продольный/поперечный формат записи

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

Повышение производительности:
    Увеличение плотности записи
        Магнито-резистивные головки
       ZBR (Zone Block Recording)
    Увеличение частоты вращение диска.
    Interleave (сейчас неактуально, потому что cache).
    Cache  (обычно кэшируется track или больше).
    Pre-fetch
    Tuning logical to physical translation.
    Reording request  (SCSI)
    RAID

  Плотность записи

Average_Seek_Time = Time_to_seek_from_0_track_to_half_of_disk +
            0.5 * Time_of_disk_one_rotation

TPI = Tracks per Inch (треков/дюйм)
BPI = Bit per Inch    (битов/дюйм)  Линейная плотность записи.

На носитель нужно записывать данные с правильной плотностью - иначе
возникают проблемы (например при увеличении плотности - peak shift)

  Структура носителя

Жесткий диск:

Так выглядит поверхность:
(справа аллюминивая, слева стекло)

Состоит как правило из нескольких блинов (пластин).
На каждой пластине 2 поверхности.

Трек - круглая дорожка на одной поверхности для операций над которой не
       надо двигать головку.

Цилиндр - совокупность треков на всех поверхностях для операций над которыми
    не надо двигать головку.

Сектор - минимальная единица чтения/записи

Высота полета головки

  Запись и чтение

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

Что происходит при записи?

Что происходит при чтении?

Примеры различных модуляций:

  FM модуляция

FM - Frequency modulation
FM = RLL 0,1

                Data	Code
        0	10
        1	11

    Data bit at center of bit cell
    Clock bit at leading edge of cell

  MFM модуляция

MFM - Modified Frequency Modulation
MFM = RLL 1,3

        Data	Code
        0	X0      (X = 1 if this and previous data = 0)
        1	01

    Data bit at center of bit cell
    Clock bit at leading edge if:
        no data in previous bit cell
        no data in current bit cell

  MMFM модуляция

MMFM = More Modified MFM

  RLL кодирование

RLL 1,7 (Run Length Limited)
        NRZ Data	Code
        01		X00
        10		010
        11		X00
        0001		X00001
        0010		X00000
        0011		010001
        0000	        010000

RLL 2,7 (Run Length Limited)
        NRZ Data	Code
        000		000100
        10		0100
        010		100100
        0010		00100100
        11		1000
        011		001000
        0011		00001000

RLL 2,7 дерево:

Сравнение: MFM и RLL

Основная идея:  Время мы можем мерить очень точно.
        А вот короткие магнитные переходы делать трудно.
        Поэтому мы кодируем данные так, что бы было как можно
        меньше переходов

BPI (Bit per Inch) при одинаковой FCI (Flux Changes per Inch)
    FM		1
    MFM		2
    RLL 1,7		2.54
    RLL 2,7		3

Еще существует ARLL (Advanced RLL) (RLL 3,9) но от его использования отказались,
т.к низкая надежность для соответсвующего уровня техники.

PRML

(Partial Response, Maximum LikeHood)
Сейчас вовсю используют PRML для распознования доменов.
Вместо того чтобы выбирать пиковые значения для напряженности магнитного
поля c помощью аналоговых схем.
DSP обрабатывает данные с диска и строит наиболее правдоподобные места
для границ доменов по аналоговым данным собранным с головки.
В результате повышается точность, что позволяет уменьшить размеры доменов.

  Многослойная поверхность

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

  Перпендикулярная запись

Один из методов повышения плотности - это перпендикулярная запись.
Дискеты ED 2.88MB 3.5" использовали именно ее.
Кроме того сейчас Toshiba стала ее использовать в HDD.

Идея перпендикулярной записи в создания магнитного поля не паралельного
а перпендикулярного плоскости media, и соответсвенно формирование не
горизонтальных, а вертикальных магнитных доменов. (+ надо увеличить
толщину магнитного слоя)
Как результат количество доменов на единицу площади возврастает.

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

  Магниторезестивные головки

MR-головки
магниторезистивные головки (Magneto Resistive) придуманы IBM,
позволили повысить плотность записи.

MR-головка является гибридом двух головок:
Для записи используется обычная индуктивная тонкопленочная головка,
для чтения используется магниторезистивный эффект:
через головку (тоже тонкопленочную) постоянно течет ток, в зависимости
от намагниченности областей над которыми двигается головка изменяется
ее сопротивление (совсем немного порядка 5%).
[тонкопленочные головки делают методом фотолитографии как микросхемы]

MR Head:

GMR Head:

  Позиционирование

Как находится нужная дорожка?

Жесткие диски:

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

Сервокоды в начале трека:
(недостаток - слишком медленно)

Сервокоды размазаны по диску.

  Wipe

Сокращение накладных расходов

GAP занимает место. Увеличиваем размер физического сектора
Общее число места занятое GAP уменьшается

То же самое с ID полями для секторов
Все равно читаем track. (NOID)

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

  Формат сектора

    Sectoring
    /      \
       Hard    Soft

Hard-sectoring применялся в 8" Floppy-disk

Синхронизация
Идентификация
Данные
Корректирующие коды
Gap (скорость не стабильна)

Сокращение накладных расходов

Увеличение размера физических секторов
NOID сектора

Ток при старте

Отказы дисков

   For more information see:
"Inside Storage and Filesystems" by PHG
[ SSDEV.CHM ]


55.10.1.1. ЛЕНТЫ

THIS SECTION IS UNDER CONSTRUCTION

      Организация дорожек
    /         |        \
  Спиральная    Линейная   Серпантинная
  Helican scan   Linear    Linear serpentine

Space mark:

  Спиральная

Плюсы: Высокая емкость, Низкая скорость записи.
       Основа: вращающиеся головки.
Вращающаяся головка:

  Линейная

ADR (Advanced Digital Recording)
    Встроенные в ленту сервосигналы
    (Записаны сигналы низкой частоты, которые проникают на большую
     глубину).
    Многоканальная головка (пишет несколько каналов сразу)

  Серпантинная

    Запись идет и при прямом и при обратном движении ленты

SPR (Symmetric Phase Recording)
Соседние треки пишутся под разными углами

  Общая организация

Есть такое понятие как File Marks, на которые можно позиционироваться.


55.10.3. МАГНИТО-ОПТИЧЕСКИЕ НОСИТЕЛИ

THIS SECTION IS UNDER CONSTRUCTION

Смешанная технология

Запись: разогрев лазером магнитного материала выше точки Кюри
    и легкое перемагничивание с помощью магнитной головки.

Чтение: поляризация луча лазера.

Плюсы:  надежность, если носитель не нагревать то магнитные поля
    практически не влияют.
    Нет контакта при чтении и записи.

Минусы: Перезапись требует стирания (хотя есть варианты магнитного
        материала когда он стирается при записи).


55.10.4. ТРЕХМЕРНАЯ ПАМЯТЬ

Сейчас есть два основных направления для трехмерной памяти:
        /              \
        Голографическое    Молекулярное

  Голографическое

(Holographic)

Базируется на записи голограмм в кристале LiNbO3
Текущая плотность (2004) 10GB/sm^3  (в пределе ~TB/sm^3)

Принцип голографии:

Запись:

Чтение:

Идея:

Запись:
разделение луча сине-зеленого аргонового лазера на две составляющие -
опорный и предметный лучи (последний является носителем самих данных).
Предметный луч подвергается расфокусировке, чтобы он мог полностью освещать
пространственный световой модулятор (SLM - Spatial Light Modulator),
который представляет собой просто жидкокристаллическую (LCD) панель,
на которой страница данных отображается в виде матрицы,
состоящей из светлых и темных пикселей (двоичные данные).
Оба луча направляются внутрь светочувствительного кристалла,
где и происходит их взаимодействие. В результате этого взаимодействия
образуется интерференционная картина, которая и является основой голограммы
и запоминается в виде набора вариаций показателя преломления или коэффициента
отражения внутри этого кристалла.

Чтение:
кристалл освещается опорным лучом, который, взаимодействуя с хранимой в
кристалле интерференционной картиной, воспроизводит записанную страницу в
виде образа "шахматной доски" из светлых и темных пикселей (
голограмма преобразует опорную волну в копию предметной).
Затем этот образ направляется в матричный детектор, основой для которого
служит прибор с зарядовой связью (CCD - Charge-Coupled Device или ПЗС),
захватывающее всю страницу данных.
При чтении данных опорный луч должен падать на кристалл под тем же самым углом,
при котором производилась запись этих данных, и допускается изменение этого
угла не более чем на градус.

Минусы:
    Слищком много голограмм - материал теряет свои свойства
    Сложная оптика

Плюсы:
    Можно паралельно читать несколько блоков

Примеры устройств прототипов:

  Молекулярная

(Protein)

THIS SECTION IS UNDER CONSTRUCTION

Так выглядет возбужденная страница:

Запись:
    Желтый страничный лазер выбирает страницу
    Переводит молекулы в Q-конформацию
    Красный лазер через маску переводит активированные молекулы в
    новое состояние
    2 лазера формируют точку
    Возбуждается молекула
    Читают флюорисценцию
    А при записи другой длинной волны и изменяется конформация.

Как это все действует:
Возьмем более простой пример: циклогексан C6H12
Он имеет два основных типа конформации: кресло и ванну

Кресло:

Ванна:

А это диаграмма его энергии:

ЭТО ЧИСТО УСЛОВНЫЙ ПРИМЕР. РЕАЛЬНЫЕ ВЕЩЕСТВА ГОРАЗДО СЛОЖНЕЕ.
Т.К. ДОЛЖНА БЫТЬ ПЕРЕЗАПИСЬ И БОЛЬШЕЕ КОЛИЧЕСТВО УСТОЙЧИВЫХ СОСТОЯНИЙ.

При записи меняем конформацию:

При чтении возбуждаем и смотрим что происходит:

А это что на самом деле:


55.10.5. ДРУГИЕ НОСИТЕЛИ

THIS SECTION IS UNDER CONSTRUCTION

    IBM разработала технологию по записи перезаписи пластика
металическими иголочками с высокой плотностью.

Запись на поверхности пластиковой пленки микроиглами.
используются иглы диаметром 10 нанометров (0,01 мкм).
первый прототип Millipede с 1024 иглами, имел емкость 0,5 Гб.

Запись:
кончик иглы нагревается до температуры в 400 градусов и плавит полимерную
пленку, оставляя точку.

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

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

Вопрос: Ведь не зря IBM продало Hitachi прибыльное подразделение по
    производству HDD?
    (Которое к тому же было лидером по технологиям)


55.11. ФАЙЛОВЫЕ СИСТЕМЫ

THIS SECTION IS UNDER CONSTRUCTION

Именование файлов.
    A:\DIRNAME\DIRNAME\FILENAME.EXT		DOS
    /DIRNAME/DIRNAME/FILENAME		UNIX
    VOLNAME:DIRNAME:DIRNAME:FILENAME	MacOS
    VOLNAME:\DIRNAME\DIRNAME\FILENAME;VER	VMS	(check it again)

    -----------------------------------------------------
    FAT		DOS, Windows, OS/2, *
    HPFS		OS/2
    NTFS		Windows NT
    Ext2/Ext3	Linux
    FFS/UFS*	FreeBSD/NetBSD/OpenBSD, Solaris, Digital UNIX
    UFS2		FreeBSD 5+
    XFS		IRIX
    HTFS		SCO OpenServer
    BeFS		BeOS
    QNX4fs		QNX
    NWFS		Novell Netware 3+
    NSS		Novell Netware 5+
    HFS/HFS+	MacOS/MacOS X
    JFS		AIX
    J2FS		AIX 5+
    ReiserFS	Linux
    VxFS		SCO UNIXware
    ODS		VMS
    ZFS		Solaris 10*
    CDFS		CD/DVD
    UDF		DVD/CD
    MTF		Tape
    -----------------------------------------------------

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

Что содержит файловая система:
    Данные файлов
    Данные директорий
    Карта распределения памяти
    Метаданные (Суперблок итд)
    Журнал транзакций
    Дисковые квоты

  Распределение дисковой памяти

Возможные реализации карты распределения памяти:

    Список блоков 		[System V]
    Bitmap			[AFS, NTFS,...]
    File Allocation Table	[FAT, NWFS]
    Не хранится на диске вычисляется в памяти [CP/M]

Список блоков:

Битовая карта блоков:

Плохие блоки:
    Помечаются в FAT		[FAT]
    Заносятся в Bad Block File	[NTFS,UNIX]

Блоки файлов:
    UNIX вариант (прямые, indirect, 2 indirect, 3 indirect) [UNIX]
    Список Extents (Runs)  [some UNIX, NTFS]
    File Allocation Table  [FAT, NWFS]

UNIX вариант:

Runs:

File Allocation Table:

  File slack

  Аттрибуты файла

Аттрибуты файла:
    Hidden
    System
    Read-only
    Compressed
    Encrypted
    Sparse
    Reparse Point (Symbolic Link)
    Device
    Pipes, IPC

  Специальные возможности

    Hard Links
    Symbolic Links
    Sparce Files
    EA (Extended Attributes)
    Multiple Streams

  Жесткие ссылки

  Символические ссылки

  Разряженные файлы

  Права доступа

Права доступа:
    UNIX  (UID,GID,File Mode)
    ACL

  Свойства тома

    User Quota
    Journaling

  Повышение быстродействия

Цель повышение производительности:

    Распыление метаданных по диску
        (чтобы модификация метаданных на приводила к seek на начало)
        [Cylinder Groups]
    Сортированные деревья

  Группы цилиндров

  Сортированные деревья

В некоторых системах используются для индексации файлов в директориях [NTFS]
В [ReiserFS 3] используются для индексации всего (все данные и метадата в томе
индексированны и находяться в одном дереве).

Деревья применяющиеся в файловых системах
    B-tree
    B+tree

Размер B-tree дерева при различных фиксированных N

Разница между B-tree и B+tree:

  FAT

  NTFS


55.11.1. КЛАСТЕРНЫЕ ФАЙЛОВЫЕ СИСТЕМЫ

THIS SECTION IS UNDER CONSTRUCTION

---------------------------------------------------------------------------
                    Драйвер файловой
Тип					системы                 Диск
---------------------------------------------------------------------------
DAS	(Direct Attached Storage) 	локальный		локальный
NAS	(Network Attached Storage)	на сервере		на сервере
SAN	(Storage Area Network)		локальный		на сервере
---------------------------------------------------------------------------

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

Как это достигается. Путем Mutual Lock диска.
Для этого служат SCSI команды:
    RESERVE UNIT
    RELEASE UNIT

Наиболее известные кластерные файловые системы:
    --------------------------------
    CFS	Vendor		Host OS
    --------------------------------
    GPFS	IBM		AIX
    CXFS	SIGI		IRIX
    --------------------------------


55.11.1. ДИСКОВЫЕ РАЗДЕЛЫ И УПРАВЛЕНИЕ ТОМАМИ

THIS SECTION IS UNDER CONSTRUCTION

    Разделы

    ----------------------------------------------------------------------
    Схемы разделов		OS			   тип		лежат на
    ----------------------------------------------------------------------
    MBR			DOS, Windows, *		   простые	PDISK
    GPT			EFI, *			   простые	PDISK
    LDM			Windows 2000+		   сложные	MBR,GPT
    Apple			MacOS/MacOS X		   простые	PDISK
    BSD Slices      	FreeBSD, NetBSD, OpenBSD   простые	MBR
    Solaris disk label	Solaris			   простые	PDISK
    OS/2 LVM                OS/2			   сложные	MBR
    LVM			Linux			   сложные	PDISK,MBR
    MD			Linux			   сложные	PDISK,MBR,GPT
    GEOM			FreeBSD			   сложные	PDISK,MBR,GPT
    SCO VTOC		SCO OpenServer		   простые	MBR
    SGI disk label		IRIX			   простые	PDISK
    -----------------------------------------------------------------------

Поддержка сложных томов:

    Система		VolSet	RAID0	RAID1	RAID4	RAID5	RAID6	RAID0+1
    -------------------------------------------------------------------
    LDM     	да	да	да	нет	да	нет	да
    OS/2 LVM	да	нет	нет	нет	нет	нет	нет
    Linux LVM	да	да	нет	нет	нет	нет	нет
    Linux MD	да	да	да	да	да	да	нет
    FreeBSD GEOM	да	да	да	да	нет	нет	нет
    --------------------------------------------------------------------

MBR:

Apple:

BSD:

LDM:

Операции над томами
    Создание
    Удаление
    Изменение размера (как правило увеличение)
    Добавление зеркала
    Удаление зеркала
    Разбиение зеркала
    Замена колонки в RAID
    ...

Snapshots
Zero Administration


55.50. ГРАФЫ

THIS SECTION IS UNDER CONSTRUCTION

Графы
граф - это совокупность объектов со связями между ними.
Объекты представляются как вершины или узлы графа, а связи - как дуги или рёбра.
Для разных областей применения, виды графов могут различаться направленностью,
ограничениями на количество связей и дополнительными данными о вершинах или рёбрах.

        Графы
          /      \
  ориентированные   неориентированные

  Ориентированный граф

Def
===
Ориентированный граф (Directed Graph)
    пара (V,E), где
        V - конечное множество			(Vertex set)
        E - бинарное отношение на V (VxV)	(Edge set)

Элементы V - называются вершинами
Элементы E - называются дугами

Обозначения:
    Вершина (Vertex) - кружок
    Ребро (Edge)	 - стрелка

Возможны циклические ребра - ребра из вершины в нее же
Ребра вида (v,v) - называются петлями

x = (v,w)  Вершина v - начало дуги x
       Вершина w - конец  дуги х
       Дуга x выходит из v и заходит в w.

  Неориентированный граф

Def
===
Неориенированный граф
    G = (V,E), где
        V - конечное множество			(Vertex set)
        а E - состоит из пар {u,v}, таких что
            u принадлежит V
            v принадлежит V
            u != v	(т.е. не содержит ребер-циклов)

Элементы V - называются вершинами
Элементы E - называются ребрами

Каждое ребро из 2х разных вершин
ребро {u,v} - говорят u смежно с v

x = {u,v}  Вершины u и v - концы ребра х.

Вершины и ребра - элементы графа

Степень вершины - количество ребер для которых она является концевой
          (при этом петли считаются дважды)

Вершина называется изолированной если она не является концом ни для какого ребра

  Пути и циклы

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

Простой путь - все вершины различны

Цикл - путь в котором начальная вершина совпадает с конечной и содержит
       хотя бы одно ребро.  (Loop)

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

Простой цикл.

Граф без циклов - Ациклический

для ориенированного графа:

  Связанный граф

Сильно связанный граф (ориентированный) - если из любой его вершины достижима
(по опиентированным путям) любая другая.

Связанный граф (неориентированный)

  Полный граф

Полный граф - неориенированный граф любая вершина которого смежна любой другой

  Лес и деревья

Ациклический неориентированный граф - лес
    Лес в принципе несвязанный
    Его связанные части - деревья
Лес - граф компонентами которого являются деревья

  Свойства

Граф называется:

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

  Иерархия графов

  Мультиграф

Мультиграф (multigraph)
    одни и те же вершины могут соединять много ребер

Одинаковые пары в G - называют кратными или паралельными ребрами.

Количество одинаковых пар (v,w) в G называют кратностью ребра (v,w)

  Псевдограф

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

  Гиперграф

Гиперграф (hypergraph)
    содержит гиперребра - соединяющие не две, а произвольное количество
    вершин

  Размеченный граф

Размеченный граф G = G(V, L, E), где
        V - Vertex set
        L - Label set
        E - подмножество множества VxLxV

Ребро (a,l,b)

Граф с весовыми коэффициентами

  Представление графа

Список смежных вершин		удобно для разряженных (sparse) графов

Матрица смежности		удобно для плотных (dence) графов

  Примитивные операции с графом

  Обход графа

  Обход в ширину

  Обход в глубину


55.51. КРАТЧАЙШИЙ ПУТЬ В ГРАФЕ

THIS SECTION IS UNDER CONSTRUCTION

Алгоритмы для Кратчайшего пути
    Из одной точки
        Алгоритм Дейкстры
        Алгоритм Белмана-Форда
        Алгоритм Йена
        Алгоритм Габова
        Алгоритм Джонсона
    Все кратчайшие пути (из всех точек во все)
        Алгоритм Форда-Уоршала

STP (Shortest Path)

INITIALIZE-SINGLE-SOURCE(G,s)
    for для всех вершин v принадлежащих V[G]
    {
        d[v] = infinity
        p[v] = NULL
    }
    d[s] = 0;

RELAX(u,v,w)
    if d[v] > d[u] + w(u,v)
    {
        d[v] = d[u] + w(u,v)
        p[v] = u
    }

  Алгоритм Дийкстры

DIJKSTRA(G,w,s)
    INITIALIZE-SINGLE-SOURCE(G,s)
    S = 0
    Q = V[G]
    while (Q != {0})
    {
        u = EXTRACT_MIN(Q)
        S = S + {u}
        for для всех вершин v принадлежащих Adj[u]
        {
            RELAX(u,v,w)
        }
    }

  Алгоритм Беллмана-Форда

BELLMAN-FORD(G,w,s)
    INITIALIZE-SINGLE-SOURCE(G,s)
    for i = 1 to |V[G]|-1
    {
        for для каждого ребра (u,v) принадлежащего E[G]
        {
            RELAX(u,w,w)
        }
    }
    for для каждого ребра (u,v) принадлежащего E[G]
    {
        if d[v] > d[u] + w(u,w)
        {
            return	false
        }
    }
    return	true

    true - в графе нет цикла отрицательного веса.
    false -  такой цикл имеется

  Алгоритм Форда-Уоршала


55.52. МИНИМАЛЬНОЕ ОСТОВНОЕ ДЕРЕВО

THIS SECTION IS UNDER CONSTRUCTION

Алгоритмы для минимального остовного дерева:
    алгоритм Крускала (Kruskal)
    алгоритм Прима (Prim)

Def
===
    Связный подграф графа G явсляющийся деревом и содержащий все его вершины
    называется покрывающим или остовным деревом (spanning tree).

Def
===
    Минимальное остовное дерево (MST - Minimal spanned tree) - остовное
    дерево с минимальным весом.

  Алгоритм Прима

MST-PRIM(G,w,r)
    Q = V[G]
    for для каждой вершины u принадлежащей Q
    {
        key[u] = infinity
    }
    key[r] = 0
    p[r] = NIL
    while (Q != {0})
    {
        u = EXTRACT_MIN(Q)
        for для каждой вершины v принадлежащей Adj[u]
        {
            if v принадлежит Q и ( w(u,v) < key[v])
            {
                p[v] = u;
                key[v] = w(u,v)
            }
        }
    }


55.53. МАКСИМАЛЬНЫЙ ПОТОК

THIS SECTION IS UNDER CONSTRUCTION

Максимальный поток
    Алгоритм Форда-Фалкерсона
    Алгоритм Эдмондса-Карпа
Поток минимальной стоимости
    TBD

  Алгоритм Форда-Фалкерсона


55.54. ПАРАЛЕЛЬНЫЕ АЛГОРИТМЫ НАД ГРАФАМИ

THIS SECTION IS UNDER CONSTRUCTION

Разделение на части
Отдельная обработка частей

Выделение необойденных вершин на каждом шаге.
Внутри шага вершины можно обрабатывать паралельно.


56. ВНЕШНИЕ УСТРОЙСТВА

THIS SECTION IS UNDER CONSTRUCTION

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


56.0. УРОВЕНЬ РЕГИСТРОВ HARDWARE

THIS SECTION IS UNDER CONSTRUCTION

Внешние устройства имеют интерфейс с компьютером
Т.е. подключены к системной шине, а на другой стороне к устройствам.
Это и есть тот самый уровень стыка hardware и software.

TODO: Bus Master Devices
      примеры нескольких простых устройств
      Возможно типовые примеры набора регистров для основных типов устройств


56.0.1. LED

THIS SECTION IS UNDER CONSTRUCTION

LED (Light Emmission Diode)

  Датчики излучения

Фотодиод

Фоторезистор

Фототранзистор

  Оптроны


56.0.2. КНОПКИ И ПЕРЕКЛЮЧАТЕЛИ

THIS SECTION IS UNDER CONSTRUCTION

Основная проблема кнопок - это дребезг.


56.0.3. СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР

THIS SECTION IS UNDER CONSTRUCTION


56.1. КЛАВИАТУРА

THIS SECTION IS UNDER CONSTRUCTION

  Сканирование матрицы клавиатуры

Проблема: нажато сразу много клавиш, ток течет неверно.
      т.е. может перетекать в другую LINE.
      Решения:
        сканировать по 1 LINE за раз
        добавить диоды

  Интерфейс клавиатуры у PC

AT-keyboard connector:

PS/2-keyboard connector:

    ---------------------------------
    Descripton	DIN5	mini-DIN6
    ---------------------------------
    KBD DATA	2	1
    GND		4	3
    Vcc (+5V)	5	4
    KBD SYNC	1	5
    NC		3	2,6
    ----------------------------------

Клавиатура обменивается с компьютером пакетами по 11-бит имееющими
следующий формат:
    ----------------------------------
    Bit	  Description
    ----------------------------------
    +00	  START BIT (Always 0)
    +01..08   DATA BITS
    +09	  PARITY BIT (Parity must be odd)
    +0A	  STOP BIT  (Always 1)
    -----------------------------------

В пакетах клавиатура пересылает скан-код клавиши которая была нажата (make-code)
или отпущена (break-code).

В Break-code установлен старший бит:
    39	     ->	B9		simple
    E0 1D        ->	E0 9D
    E0 2A E0 52  ->	E0 D2 E0 AA
    pause	     -  none break code

Пример scan-кодов:

        Normal	Shift
    01	Esc
    02	1  	!
    03	2  	@
    04	3	#
    05	4	$
    06	5	%
    07	6	^
    08	7	&
    09	8	*
    0A	9	(
    0B	0	)
    0C	-	_
    0D	=	+
    0E	BS
    0F	TAB
    10	q	Q
    11	w	W
    12	e	E
    13	r	R
    14	t	T
    15	y	Y
    16	u	U
    17	i	I
    18	o	O
    19	p	P
    1A	[	{
    1B	]	}
    1C	ENTER
     E0 1C	ENTER		(num)
    1D	CTRL
     E0 1D	R-CTRL
    1E	a	A
    1F	s	S
    20	d	D
    21	f	F
    22	g	G
    23	h	H
    24	j	J
    25	k	K
    26	l	L
    27	;	:
    28	"	'
    29	`	~
    2A	L-SHIFT
    2B	\	|
    2C	z	Z
    2D	x	X
    2E	c	C
    2F	v	V
    30	b	B
    31	n	N
    32	m	M
    33	,	<
    34	.	>
    35	/	?
     E0 35	/		(num)
    36	R-SHIFT
    37	*		(num)
    38	ALT
     E0 38	R-ALT
    39	SPACE
    3A	CAPS LOCK
    3B	F1
    3C	F2
    3D	F3
    3E	F4
    3F	F5
    40	F6
    41	F7
    42	F8
    43	F9
    44	F10
    45	NUM LOCK
    46	SCROLL LOCK
    47	HOME    	[7]
    48	UP      	[8]
    49	PGUP		[9]
    4A	-		(num)
    4B	LEFT    	[4]
    4C	                [5]
    4D	RIGHT           [6]
    4E	+               (num)
    4F	END             [1]
    50	DOWN            [2]
    51	PGDN            [3]
    52	INS             [0]
    53	DEL             [.]
    54	SYSRQ
    56	MACRO
    57	F11
    58	F12
    5A	PA1
    5B	F13/LWin
    5C	F14/RWin
    5D	F15/Menu
    63	F16
    64	F17
    65	F18
    66	F19
    67	F20
    68	F21
    69	F22
    6A	F23
    6B	F24
        6D	EraseEOF
    6F	Copy/Play
    72	CrSel
    73	Delta
    74	ExSel
    76	Clear

    E0 38	R-ALT
    E0 1D	R-CTRL

    E0 2A E0 52	Ins
    E0 2A E0 47	Home
    E0 2A E0 49	Page Up
    E0 2A E0 53	Del
    E0 2A E0 4F	End
    E0 2A E0 51     Page Down
    E0 2A E0 48	Up
    E0 2A E0 4B	Left
    E0 2A E0 50	Down
    E0 2A E0 4D	Right

    E0 2A E0 37	Print Scr
    E1 1D 45 E1 9D C5	Pause	(no break code)

специальные коды:

    00	- Buffer overflow
    AA	- Self test Ok
    AB 83   - keyboard id
    E0	- grey key pfix
    E1	- pfix for not break code
    F0	- break pfix
    EE	- echo
    FA	- ack
    FC	- self test error
    FD	- self test error
    FE	- resend
    FF	- keyboard error (code set 1)

коды для multimedia-клавиатур:

    E0 01		My Documents
    E0 05		Messager
    E0 07		Redo/F15
    E0 08		Undo/F14
    E0 0A		Paste
    E0 10		Previous Track or IE Back
    E0 13		Word
            Online Community (COMPAQ) [people icon]
    E0 14		Excel
            Online Compaq  (COMPAQ)  [Q icon]
    E0 15		Online Service (COMPAQ)  [Bulb icon]
    E0 16		Log Off
    E0 18		Open faivorites (Logitech)
    E0 19		Next Track or IE Next
    E0 1E		Mail (COMPAQ) [Envelope icon]
    E0 20		Mute
    E0 21		Calculator	[on COMPAQ search]
    E0 22		Play/Pause
    E0 23		Spell/F22	[on COMPAQ start button]
    E0 24		Stop
    E0 26		Add faivourite (Logitech)
    E0 2E		Volume Down
    E0 2C		Eject
    E0 30		Volume Up
    E0 32		WWW Home
    E0 3B		Help/F13
    E0 3C		My Music
    E0 3E		New/F16
    E0 3F		Open/F17
    E0 40		Close/F18
    E0 41		Reply/F19
    E0 42		Forware/F20
    E0 43		Send/F21

    E0 57		Save/F23
    E0 58		Print/F24
    E0 5E		Power Off
    E0 5F		Sleep
    E0 63		Wake
    E0 64		My Pictures
    E0 65		WWW Search
    E0 66		WWW Faivourites
    E0 67		WWW Refresh
    E0 68		WWW Stop
    E0 69		WWW Forward
    E0 6A		WWW Back
    E0 6B		My Computer
    E0 6C		E-mail
    E0 6D		Media select

  Раскладки клавиатуры

    Qwerty
    Dworak
    Jcuken

Qwerty - исторически сложилась пришла с печатных машинок 1878
при быстрой печати - западали буквы. Поэтому старались раздвинуть.

Qwertz - немецкая модификация qwerty
Y и Z поменялись местами и вместо скобок несколько более популярных символов
со всякими там умляутами.

Azerty - французко-бельгийская модификация qwerty
A и Q поменяны местами, Z и W - тоже, M,N - подвинуты.

Dworak - более эргономичная 1930s. Часто используемые буквы расположены в
середине. Скорость печати выше чем у qwerty.

у русской клавиатуры один и тот-же layout. Он применяется и на Qwerty
и на JCUKEN


56.2. ВИДЕО ВЫВОД

THIS SECTION IS UNDER CONSTRUCTION

  Видеоконтроллер

Video Adapter в графическом режиме:

Video Adapter в текстовом режиме:

VGA 15-pin (VGA = Video Graphic Array)
 ---------------------------------------------------------------
pin	name		description		alt. description
 ---------------------------------------------------------------
1	RED		Red video
2	GREEN		Green video
3	BLUE		Blue video
4	N/C					Monitor ID (2)
5	GND		Ground (HSync)		Ground
6	RED_RTN		Red return		Red Ground
7	GREEN_RTN       Green Return		Green Ground
8	BLUE_RTN	Blue Return		Blue Ground
9	+5V		+5V (DDC)		[KEY]
10	GND		Ground (VSync, DDC)	Sync Ground
11	N/C					Monitor ID (1)
12	SDA		I2C DDC data		Monitor ID (0)
13	HSYNC		Horizontal Sync
14	VSYNC		Vertical Sync
15	SCL		I2C DDC clock		N/C
 ---------------------------------------------------------------
DDC1 = Unidirectional
DDC2 = Bidirectional

Более старый вариант 9-pin

 ----------------------------------
pin	name	description
 ----------------------------------
1 	RED  	Red Video
2 	GREEN 	Green Video
3 	BLUE  	Blue Video
4 	HSYNC  	Horizontal Sync
5 	VSYNC  	Vertical Sync
6 	RGND  	Red Ground
7 	GGND  	Green Ground
8 	BGND  	Blue Ground
9 	SGND  	Sync Ground
 ----------------------------------

 ---------------------------------------------------
pin	description
 ---------------------------------------------------
1	TMDS Data 2-		Digital Red-   (1)
2	TMDS Data 2+		Digital Red+   (1)
3	TMDS Data 2/4 shield
4	TMDS Data 4-		Digital Green- (2)
5	TMDS Data 4+		Digital Green+ (2)
6	DDC Clock
7	DDC Data
8	Analog VSYNC
9	TMDS Data 1-		Digital Green- (1)
10	TMDS Data 1+		Digital Green+ (1)
11	TMDS Data 1/3 shield
12	TMDS Data 3-		Digital Blue-  (2)
13	TMDS Data 3+		Digital Blue+  (2)
14	+5V (power for monitor snandby)
15	GND (for pin14 and analog sync)
16	Hot plug detect
17	TMDS Data 0-		Digital Blue-  (1)
18	TMDS Data 0+		Digital Blue+  (1)
19	TMDS Data 0/5 shield
20	TMDS Data 5-		Digital Red-   (2)
21	TMDS Data 5+		Digital Red+   (2)
22	TMDS clock shield
23	TMDS clock+		Digital clock+
24	TMDS clock-		Digital clock-
C1	Analog Red
C2	Analog Green
C3	Analog Blue
C4	Analog HSYNC
C5	Analog Ground (for Red, Green, Blue)
 ---------------------------------------------------

TMDS = Transaction Minimized Differental Signaling
       non-standart form of 8B/10B encoding

DB13W3
 ---------------------------------------------------
pin		Description:Sun Description:SGI
 ---------------------------------------------------
1		GND		Monitor ID 3/SCL
2		VSYNC		Monitor ID 0/SDA
3		Sense 2		Composite Sync
4		Sense ground	HSYNC
5		Composite sync	VSYNC
6		HSYNC		Monitor ID 1/DDC +5V
7		GND		Monitor ID 2/DDC ground
8		Sense 1		Ground
9		Sense 0		Ground
10		Composite gnd	Sync Ground
A1		Red		Red
A2		Green		Green
        Gray for monochrome
A3		Blue		Blue
 ---------------------------------------------------

Composite
1	+
2	-

S-Video
 -------------------------------------
pin	description
 -------------------------------------
1	Ground (Y)
2	Ground (C)
3	Y	Intency (Lumminance)
4	C	Color (Chrominance)
 -------------------------------------

VGA Timing
 --------------------------------------------------------------------
     Pixel       Horizontal (in pixels)     Vertical (in lines)
           Clock	     Active Front Sync  Back    Active Front Sync  Back
Format   MHz         Video  Porch Pulse Porch   Video  Porch Pulse Porch
 --------------------------------------------------------------------
640x480  60Hz 25.175 640    16    96    48      480    11    2     31
640x480  72Hz 31.500 640    24    40    128     480    9     3     28
640x480  75Hz 31.500 640    16    96    48      480    11    2     32
640x480  85Hz 36.000 640    32    48    112     480    1     3     25
800x600  56Hz 38.100 800    32    128   128     600    1     4     14
800x600  60Hz 40.000 800    40    128   88      600    1     4     23
800x600  72Hz 50.000 800    56    120   64      600    37    6     23
800x600  75Hz 49.500 800    16    80    160     600    1     2     21
800x600  85Hz 56.250 800    32    64    152     600    1     3     27
1024x768 60Hz 65.000 1024   24    136   160     768    3     6     29
1024x768 70Hz 75.000 1024   24    136   144     768    3     6     29
1024x768 75Hz 78.750 1024   16    96    176     768    1     3     28
1024x768 85Hz 94.500 1024   48    96    208     768    1     3     36
 --------------------------------------------------------------------

 --------------------------------------------------------------------
VGA 	Video graphics array 			640 x 480
SVGA 	Super video graphics array 		800 x 600
XGA 	Extended graphics array 		1024 x 768
SXGA 	Super extended graphics array 		1280 x 1024
UXGA 	Ultra extended graphics array 		1600 x 1200
WXGA 	Wide extended graphics array 		1366 x 768
WSXGA 	Wide super extended graphics array 	1680 x 1050
WUXGA 	Wide ultra extended graphics array 	1920 x 1200
 --------------------------------------------------------------------

Блок-схема адаптера типа VGA:

    Library ieee;
    Use ieee.std_logic_1164.all;

    Entity vga is
        Port (
            Clk : IN std_logic;
            Nrst : IN std_logic;
            Hsync : OUT std_logic;
            Vsync : OUT std_logic;
            Red : OUT std_logic_vector (1 downto 0);
            Green : OUT std_logic_vector (1 downto 0);
            Blue : OUT std_logic_vector (1 downto 0);
            Address : OUT (std_logic_vector (15 downto 0);
            Data : IN (std_logic_vector (7 downto 0);
            RAM_en : OUT std_logic;
            RAM_oe : OUT std_logic;
            RAM_wr : OUT std_logic
        );
    End entity vga;

    Architecture core of vga is
        -- VGA internal signals go here
    Begin
        -- VGA Interface core goes here
    End architecture core;

    Mem_read : process ( pclk, nrst ) is
        signal current_address : unsigned (16 downto 0);
    Begin
        If nrst = '0' then
            Pixelcount <= 0;
            Current_address <= 0;
        Else
            If rising_edge(pclk) then
                Current_address <= current_address + 1;
                Address <= std_logic_vector(current_address);
                Pixel_data <= data;
            End if;
        End if;
    End process;

    signal pixel_data : std_logic_vector ( 7 downto 0 );

    Hsync_counter : process ( clk, nrst ) is
        Hcount : unsigned ( 11 downto 0 );
    Begin
        If nrst = '0' then
            Hcount <= 0;
            Hsync <= '1';
        Else
            If hcount > and hcount < 2988 then
                hsync <= '0';
            else
                hsync <= '1';
            End if;
            If hcount < 3177 then
                Hcount <= hcount + 1;
            Else
                Hcount <= 0;
            End if;
        End if;
    End process;

    Clk_div : process ( clk, nrst ) is
    Begin
        If nrst = '0' then
            Count <= 0;
            Vclk <= '0';
        Else
            If count = 1999 then
                Count <= 0;
                Vclk <= not vclk;
            Else
                Count <= count + 1;
            End if;
        End if;
    End process;

    Vsync_timing : process (vclk) is
    Begin
        If nrst = '0' then
            Vcount <= 0;
        Else
            If vcount>15700 and vcount < 15764 then
                Vsync <= '0';
            Else
                Vsync <= '1';
            End if;
            If vcount > 16784 then
                Vcount <= 0;
            Else
                Vcount <= vcount + 1;
            End if;
        End if;
    End process;

    Hblank_counter : process ( clk, nrst ) is
        Hcount : unsigned ( 11 downto 0 );
    Begin
        If nrst = '0' then
            Hcount <= 0;
            hblank <= '1';
        Else
            if hcount > 2517 and hcount < 3177 then
                hblank <= '0';
            else
                hblank <= '1';
            End if;
            If hcount < 3177 then
                Hcount <= hcount + 1;
            Else
                Hcount <= 0;
            End if;
        End if;
    End process;

    Vblank_timing : process (vclk) is
    Begin
        If nrst = '0' then
            Vcount <= 0;
            Vblank<='1';
        Else
            If vcount > 15250 and vcount < 16784 then
                vblank <= '0';
            Else
                vblank <= '1';
            End if;
            If vcount > 16784 then
                Vblank <= 0;
            Else
                Vcount <= vcount + 1;
            End if;
        End if;
    End process;

    Pixel_handler : process (pclk) is
    Begin
        Red <= data(1 downto 0);
        Green <= data(3 downto 2);
        Blue <= data(5 downto 4);
    End process;

    Pixel_handler : process (pclk) is
        Blank : std_logic_vector (1 downto 0);
    Begin
        Blank(0) <= hblank or vblank;
        Blank(1) <= hblank or vblank;
        Red <= data(1 downto 0) & blank;
        Green <= data(3 downto 2) & blank;
        Blue <= data(5 downto 4) & blank;
    End process;

Типичные регистры CRT контроллера (CGA):
00	Horizontal Total Register
    (Число знако-мест на одной линии сканирования,
    включая обратный ход луча)
01	Horizontal Display Enable End Register
02	Horyzontal Sync Position
03	Horyzontal Sync Pulse Width
04	Vertical Raws
05	Vertical Total Adjust
06	Vertical Displayed
07	Vertical Sync Position
    (начало обратного хода луча)
08	Interlase Mode Register
09	Max Scan-line register
0A	Cursor Start register
0B	Cursor End register
0C,0D	Start Address of Video Memory
0E,0F	Cursor Location register

GPU

CRT controller.
Видео-интерфейсы

  Монитор

  CRT монитор

CRT (Cathode Ray Tube)

  LCD монитор

LCD (Liquid Cristal Display)

Принцип работы:

Активная матрица:

Особенности размещения:

  Электронные чернила


56.2.1. GPU

GPU = Graphics Processor Unit

Что делает GPU?

  ATI X700

ATI X700:

  NVIDIA 6800

Типовые команды для Vertex Shader (DirectX 9):

add	dest,src1,src2		dest = src1 + src2
dp3	dest,src1,src2		dest.x=dest.y=dest.z=dest.w=
                (src1.x*src2.x)+(src1.y*src2.y)+(src1.z*src2.z)
dp4	dest,src1,src2		same but +(src1.w*src2.w)
dst	dest,src1,src2		Calculate distance vector
expp	dest,src.w		dest.x = 2 ** (int) src.w
                dest.y = mantissa(src.w)
                dest.z = expp(src.w)
                dest.w = 1.0
lit	dest,src		Calculate lighning coefficients
logp	dest,src.w		Logarithm 10-bit precision
mad	dest,src1,src2,src3	dest = (src1*src2) + src3
max	dest,src1,src2		dest=(src1>=src2)? src1 : src2
min	dest,src1,src2		dest=(src1=src2)?1:0
slt	dest,src1,src2		dest=(src1

Типовые команды для Pixel Shader (DirectX 9):
tex	d			Load color data 	RGBA
texbem	d,s
texbeml	d,s			apply additional luminscense
texcoord	d
texdp3	d,s
texdp3tex	d,s
texkill	s
texm3x2depth	d,s
texm3x2pad	d,s
texm3x2tex	d,s
texm3x3		d,s
texm3x3pad	d,s
texm3x3spec	d,s1,s2
texm3x3tex	d,s
texm3x3vspec	d,s
texreg2ar	d,s
texreg2gb	d,s
texreg2rgb	d,s

texcrd		d,s
texdepth	d
texkill		s
texld		d,s

add		d
add		s0,s1
bem		d
cmp		d
cnd
dp3
dp4
lrp
mad
mov
mul

GPU

  Набор команд GPU на примере ATI R700

Наборы команд GPU реально ориенированы на DirectX,
при этом даже представление FP. NaN - DirectX ориентированное.

--------- Control-----
ALU		Initialize ALU clause
ALU_BREAK	Initialize ALU clause, loop break
ALU_CONTINUE	Initialize ALU clause, continue unmasked pixels
ALU_ELSE_AFTER	Initialize ALU clause, stack push and else after
ALU_POP_AFTER	Initialize ALU clause, pop stack after
ALU_POP2_AFTER	Initialize ALU clause, pop stack twice after
ALU_PUSH_BEFORE	Initialize ALU clause, stack push before
CALL		Call subroutine
CALL_FS		Call fetch subroutine
CUT_VERTEX	End primitive strip, start new primitive strip
ELSE		else
EMIT_CUT_VERTEX	Emit vertex, end primitive strip
EMIT_VERTEX	Vertex exported to memory
EXPORT		Export from VS or PS
EXPORT_DONE	Export last data
JUMP		Jump to address
KILL		Kill pixels conditional
LOOP_BREAK	Break out of innermost loop
LOOP_CONTINUE	Continue loop
LOOP_END	End loop
LOOP_START	Start loop
LOOP_START_DX10	Start loop direct X 10
LOOP_START_NO_AL Enter loop if zero, no push
MEM_EXPORT	Access scatter buffer
MEM_REDUCTION	Access reduction buffer
MEM_RING	Write ring buffer
MEM_SCRATCH	Access scratch buffer
MEM_STREAM0	Write stream buffer 0
MEM_STREAM1	Write stream buffer 1
MEM_STREAM2
MEM_STREAM3
NOP		No operation
POP		Pop from stack
PUSH		Push state to stack
PUSH_ELSE	Push state to stack and invert state
RETURN		Return from subroutine
TEX		Initiate texture-fetch clause
VTX		Initiate vertex-fetch clause
VTX_TC		Initiate vertex-fetch clause through texture cache
WAIT_ACK	Wait for write or fetch-read ACK

---- Arithmetic---
ADD		Add floating point
ADD_64		Add floating point 64-bit
ADD_INT		Add integer
AND_INT		And bitwize
ASHR_INT	Scalar arithmetic shift right
CEIL		FP ceiling
CMOVE		FP conditional move if equal
CMOVE_INT	integer conditional move if equal
CMOVGE
CMOVGE_INT
CMOVGT
CMOVGT_INT
COS		Scalar cosine
CUBE		Cube map
DOT4		Four elements dot product
DOT4_IEEE	Four elements dot product IEEE rules
EXP_IEEE	Scalar 2-based exponent
FLOOR		FP floor
FLT_TO_INT	FP to integer
FLT32_TO_FLT64	FP 32-bit to FP 64-bit
FLT64_TO_FLT32
FRACT		FP Fractional			// dst = src0 - FLOOR(scr0)
FRACT_64	FP Fractional 64-bit
FREXP_64	Split 64-bit FP into fractional and exponent
INT_TO_FLT
KILLE		FP pixel kill if equal
KILLGE
KILLGT
KILLNE
LDEXP_64	Combine separate fraction and exponent into 64-bit FP
LOG_CLAMPED	Scalar base-2 logarithm
LOG_IEEE	Scalar base-2 IEEE logarithm
LSHL_INT	Scalar logical shift left
LSHR_INT	Scalar logical shift right
MAX		FP maximum
MAX_DX10	FP maximum DirectX 10 (other method of handling NaNs)
MAX_INT		Integer maximum
MAX_UINT	Unsigned integer maximum
MAX4		Four elements maximum
MIN		FP minimum
MIN_DX10
MIN_INT		Integer minimum
MIN_UINT
MOV		Copy to GPR
MOVA		Copy FP to integer in AR or GPR
MOVA_FLOOR	Copy truncated FP to integer in AR or GPR
MOVA_INT	Copy signed integer to integer in AR or GPR
MUL		FP Multiply
MUL_64
MUL_IEEE
MUL_LIT		Scalar multiply emulating LIT operation
MUL_LIT_D2	Scalar multiply emulating LIT, divide by 2
MUL_LIT_M2	Scalar multiply emulating LIT, multiply by 2
MUL_LIT_M4
MULADD		FP Multiply-add
MULADD_64
MULADD_D2	FP Multiply-add, divide by 2
MULADD_M2
MULADD_M4
MULADD_IEEE
MULADD_IEEE_D2
MULADD_IEEE_M2
MULADD_IEEE_M4
MULHI_INT	Signed scalar multiply hi-order 32-bit
MULHI_UINT	Unsigned scalar multiply hi-order 32-bit
MULLO_INT	Signed scalar multiply lo-order 32-bit
MULLO_UINT	Unsigned scalar multiply lo-order 32-bit
NOP
NOT_INT		Bitwize NOT
OR_INT		Bitwize OR
PRED_SET_CLR	Predicate counter clear
PRED_SET_INV	Predicate counter invert
PRED_SET_POP	Prediacte counter POP
PRED_SET_RESTORE Predicate counter restore
PRED_SETE	Prediacte counter set if equal
PRED_SETE_64
PRED_SETE_INT
PRED_SETE_PUSH	FP predicate counter increment if equal
PRED_SETE_PUSH_INT
PRED_SETGE
PRED_SETGE_64
PRED_SETGE_INT
PRED_SETGE_PUSH
PRED_SETGE_PUSH_INT
PRED_SETGT
PRED_SETGT_64
PRED_SETGT_INT
PRED_SETGT_PUSH
PRED_SETGT_PUSH_INT
PRED_SETLE_INT
PRED_SETLE_PUSH_INT
PRED_SETLT_INT
PRED_SETLT_PUSH_INT
PRED_SETNE
PRED_SETNE_64
PRED_SETNE_INT
PRED_SETNE_PUSH
PRED_SETNE_PUSH_INT
RECIP_CLAMPED	Scalar reciprocal, clamp to maximum
RECIP_FF	Scalar reciprocal, clamp to zero
RECIP_IEEE
RECIP_INT	Signed integer scalar reciprocal
RECIP_UINT
RECIPSQRT_CLAMPED
RECIPSQRT_FF
RECIPSQRT_IEEE
RNDNE		Round to nearest even integer
SETE		FP set if equal
SETE_DX10
SETE_INT
SETGE
SETGE_DX10
SETGE_INT
SETGE_UINT
SETGT
SETGT_DX10
SETGT_INT
SETGT_UINT
SETNE
SETNE_DX10
SETNE_INT
SIN		Scalar sine
SQRT_IEEE
SUB_INT		Integer subtract
TRUNC		FP Truncate
UINT_TO_FLT
XOR_INT		bitwize XOR

---vertex-fetch---
FETCH		Vertex fetch
SEMANTIC	Semantic vertex fetch

GET_COMP_TEX_LOD	Get computed level of detail for pixels
GET_GRADIENTS_H		Get slopes relative to horizontal
GET_GRADIENTS_V
GET_NUMBER_OF_SAMPLES
GET_TEXTURE_RESINFO
KEEP_GRADIENTS
LD		Load texture elements
MEM		Memory read
SAMPLE		Sample texture
SAMPLE_C	Sample texture with comparation
SAMPLE_C_G	Sample texture with comparation and gradient
SAMPLE_C_G_L	Sample texture with comparation, gradient and LOD
SAMPLE_C_G_LB	Sample texture with comparation, gradient and LOD bias
SAMPLE_C_G_LZ	Sample texture with comparation, gradiant and LOD zero
SAMPLE_C_L	Sample texture with LOD
SAMPLE_C_LB	Sample texture with LOD bias
SAMPLE_C_LZ	Sample texture with LOD zero
SAMPLE_G	Sample texture with gradient
SAMPLE_G_L
SAMPLE_G_LB
SAMPLE_G_LZ
SAMPLE_L
SAMPLE_LB
SAMPLE_LZ
SET_CUBEMAP_INDEX
SET_GRADIENTS_H
SET_GRADIENTS_V

SCRATCH		Read scratch buffer
REDUCTION	Read reduction buffer
SCATTER		Read scatter buffer

LOCAL_DS_WRITE	Local data share write
LOCAL_DS_READ


56.3. УСТРОЙСТВА ВВОДА

THIS SECTION IS UNDER CONSTRUCTION

  2D устройства ввода

    - Mouse					relative position
    - Trackball

    - Joystick
    - Digitizer/Tablet/Touch pad		absolute position

    - Light Pen
    - Touch Screen

  Мышь

Принцип работы мыши:

Принцип работы оптической мыши:

Что видит оптическая мышь:

Trackball:

Serial Mouse connector

DB9	DB25	Mouse Signal		COM-port signal
2	3	Data			RD
5	7	GND			GND
7(4)	4(20)	+Vcc			RTS(DTR)
3	2	-Vcc			TD

PS/2 Mouse connector

   /--+--\ 		1	Mouse Data
 / 6 X  5 \             2
 |4  X   3|             3	GND
 \ 2   1 /              4	Vcc (+5V)
  +-----+               5	Mouse clock
                        6

SERIAL MOUSE PROTOCOLS

  Microsoft Serial Mouse

Microsoft Serial Mouse have 2 buttons.
1200 baud, 7 bit word len, parity off

   6    5    4    3    2    1    0
+----+----+----+----+----+----+----+
|  1 |  L |  R | Y7 | Y6 | X7 | X6 |   +0000
+----+----+----+----+----+----+----+
|  0 | X5 | X4 | X3 | X2 | X1 | X0 |   +0001
+----+----+----+----+----+----+----+
|  0 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 |   +0002
+----+----+----+----+----+----+----+

  Microsoft Serial Mouse +

Microsoft Serial Mouse+ have 3 buttons.
1200 baud, 7 bit word len, parity off

   6    5    4    3    2    1    0
+----+----+----+----+----+----+----+
|  1 |  L |  R | Y7 | Y6 | X7 | X6 |   +0000
+----+----+----+----+----+----+----+
|  0 | X5 | X4 | X3 | X2 | X1 | X0 |   +0001
+----+----+----+----+----+----+----+
|  0 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 |   +0002
+----+----+----+----+----+----+----+
|  0 |  M |  0 |  0 |  0 |  0 |  0 |   +0003
+----+----+----+----+----+----+----+

  3D Serial Mouse

1200 baud, 7 bit word len, parity off

   6    5    4    3    2    1    0
+----+----+----+----+----+----+----+
|  1 |  L |  R | Y7 | Y6 | X7 | X6 |   +0000
+----+----+----+----+----+----+----+
|  0 | X5 | X4 | X3 | X2 | X1 | X0 |   +0001
+----+----+----+----+----+----+----+
|  0 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 |   +0002
+----+----+----+----+----+----+----+
|  0 |  0 | R0 | Z3 | Z2 | Z1 | Z0 |   +0003
+----+----+----+----+----+----+----+

  PC Mouse

PC Mouse have 3 buttons.
1200 baud, 8 bit, parity off

  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|  1 |  0 |  0 |  0 |  0 |  L |  M |  R |   +0000
+----+----+----+----+----+----+----+----+
| X7'| X6'| X5'| X4'| X3'| X2'| X1'| X0'|   +0001
+----+----+----+----+----+----+----+----+
| Y7'| Y6'| Y5'| Y4'| Y3'| Y2'| Y1'| Y0'|   +0002
+----+----+----+----+----+----+----+----+
| X7"| X6"| X5"| X4"| X3"| X2"| X1"| X0"|   +0003
+----+----+----+----+----+----+----+----+
| Y7"| Y6"| Y5"| Y4"| Y3"| Y2"| Y1"| Y0"|   +0004
+----+----+----+----+----+----+----+----+

PS/2 MOUSE PROTOCOLS

  PS/2 Standart Mouse

  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
| YV | XV | YS | XS |  1 | M' |  R |  L |   +0000
+----+----+----+----+----+----+----+----+
| X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 |   +0001
+----+----+----+----+----+----+----+----+
| Y7 | Y6 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 |   +0002
+----+----+----+----+----+----+----+----+

  3D PS/2 Mouse

  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|  0 |  0 | YS | XS |  1 |  M |  R |  L |   +0000
+----+----+----+----+----+----+----+----+
| X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 |   +0001
+----+----+----+----+----+----+----+----+
| Y7 | Y6 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 |   +0002
+----+----+----+----+----+----+----+----+
| Z7 | Z6 | Z5 | Z4 | Z3 | Z2 | Z1 | Z0 |   +0003
+----+----+----+----+----+----+----+----+

  PS/2 Wheel Mouse

  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|  0 |  0 | YS | XS |  1 |  M |  R |  L |   +0000
+----+----+----+----+----+----+----+----+
| X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 |   +0001
+----+----+----+----+----+----+----+----+
| Y7 | Y6 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 |   +0002
+----+----+----+----+----+----+----+----+
|  0 |  0 | B5 | B4 | Z3 | Z2 | Z1 | Z0 |   +0003
+----+----+----+----+----+----+----+----+

USB MOUSE PROTOCOLS

USB Mouse is HID device:

    03h	class		HID
    01h	subclass        BootDevices
    02h	protocol	Mouse

Mouse send Reports via Interrupt transfers.

Here is format of first bytes of report:
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|  Vendor specific       | M  | R  | L  |   +0000
+----+----+----+----+----+----+----+----+
| X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 |   +0001
+----+----+----+----+----+----+----+----+
| Y7 | Y6 | Y5 | Y4 | Y3 | Y2 | Y1 | Y0 |   +0002
+----+----+----+----+----+----+----+----+
=					=
+----+----+----+----+----+----+----+----+

  Touch Pad

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

Примеры пакета TouchPad в режиме относительных координат:

Примеры пакета TouchPad в режиме абсолютных координат:

  Джойстик

(а так же руль с педалями)

смотри также секцию 56.9 - Game Port.

Раньше Joystikи вешались на Game Port.
Сейчас это USB устройства c стандартизированным протоколом.

Формат репорта Joysticka:

USB Joystick is HID Device.
    03h	class		HID
    01h	subclass        BootDevices
    04h	protocol	Joystick

  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|            X Position			|
+----+----+----+----+----+----+----+----+
|            Y Position                 |
+----+----+----+----+----+----+----+----+
| B4 | B3 | B2 | B1 |                   |
+----+----+----+----+----+----+----+----+
|             Throttle			|
+----+----+----+----+----+----+----+----+

Joystikи c большем числок кнопок, рули педали
имеют расширенные версии репорта - но они уже device depended.

  3D устройства ввода

    - Dataglove (6 degree of freedom)
    - Head mounting display
    - Space ball


56.4. ПРИНТЕР

THIS SECTION IS UNDER CONSTRUCTION

       Принтер
    /    |       \
   Матричный Струйный Лазерный

       Принтер
     /       \
   Монохромный  Цветной

  Струйный

Термическая головка

Пьезоголовка

InkJet
Dye Sublimation

  Лазерный

Частица тонера:

  Матричный

Управление принтером

Основные системы команд принтеров

    ESC/P	Epson
    PCL	HP
    IBM/P	IBM		устарел

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

Мы приведем здесь кратко набор команд PCL:
-----------------------------------------------------------------
Esc E			Reset
Esc &l # X		Number of copies
Esc &l # S		Simplex/Duplex Print
Esc &l # U		Left (Long-Edge) Offset Registration
Esc &l # Z		Top (short-edge) offset registration
Esc &u # D		Unit of Measure
Esc *o # Q		Mechanical Print Quality
Esc &l # M		Media Type
Esc &a # N		Negative Motion
-----------------------------------------------------------------
Esc &l # A		Page Size
Esc &l # O		Orientation (Portrait/Langscape)
Esc &a # G		Page Side Selection
Esc &l T		Job Separation
Esc &l # H		Media Source
Esc &l # G		Output (Media) bin
Esc &a # P		Print Direction
Esc &c # T		character text path dir.
Esc &a # L		Left margin
Esc &a # M		Rigth margin
Esc 9			Clear horizontal margins
Esc &l # E		Top Margin
Esc &l # F		Text Margin
Esc &l # L		Perforation skip
Esc &k # H		Horizontal Motion Index
Esc &l # C		Vertical Motion Index
Esc &l # D		Line Spacing
-----------------------------------------------------------------
Esc &a # C		Horizontal position
Esc *p # X
Esc &a # H
Esc &a # R		Vertical Position
Esc *p # Y
Esc &a # V
Esc =			Half Line Feed
Esc &k # G		Line termination
Esc &f # S		Push/Pop selection
Esc ( ID		Symbol set (primary)
Esc (s # P		Spacing (primary)
Esc (s # H		Pitch (primary)
Esc (s # V		Heigth (primary)
Esc (s # S		Style (primary)
Esc (s # B		Stroke Weigth (primary)
Esc (s # T		Typeface (primary)
Esc (s # X		Font selection by id
Esc (3 @		Select default font
Esc &d # D		Underline
Esc &d @
Esc &p # X [data]	Transparent Print Data
Esc &t # P		Text Parsing method
Esc *c # D		Assign font ID
Esc *c # F		font control
Esc *c # R		Symbol set ud code
Esc (f # W [data]	Define symbol font
Esc *c # S		Symbol set control
-----------------------------------------------------------------
Esc )s # W [data]	Font descriptor
Esc *c # E		Character code
Esc (s # W [data]	Download character
Esc &f # Y		macro id
Esc &f # X		macro control
Esc *v # N		source transparency mode
Esc *v # O		pattern transparency mode
Esc *c # G		Arer Fill (pattern) ID
Esc *v # T		Select current pattern
Esc *l # O		logical opration
Esc *l # R		pixel placement
Esc *c # W [data]	Define (download) pattern
Esc *p # R		set pattern reference point
Esc *c # Q		user-defined pattern control
-----------------------------------------------------------------
Esc *t # R		raster resolution
Esc *r # F		graphics presentation
Esc *r # T		raster height (sources)
Esc *t # V		raster height (destination)
Esc *r # S		raster width (source)
Esc *t # H		raster width (destination)
Esc *t # K		scale algorithm
Esc *r # A		start raster graphics
Esc *b # Y		Y offset
Esc *b # M		set compression mode
Esc *b # W [data]	transfer raster (row/block)
Esc *b # V [data]	transfer raster (plane)
Esc *r B		End graphics
Esc *r C		End graphics (version C - preferrable)
-----------------------------------------------------------------
Esc *c # A		Horizontal rectangle size
Esc *c # H
Esc *c # B		Vertical ractangle size
Esc *c # V
Esc *c # G		Pattertn ID (Area fill ID)
Esc *c # P		Fill rectanlge area
Esc *s # T		Set status readback location type
Esc *s # U		Set status readback location unit
Esc *s # I		Inquiry status readback entry
Esc *s 1 M		Free space
Esc &r # F		Flush all pages
Esc *s # X		Echo
Esc *c # X		Picture frame horizontal size
Esc *c # Y		picture frame vertical size
Esc *c 0 T		set picture frame anchor point
Esc *c # K		set HP-GL/2 horizontal plot size
Esc *c # L		set HP-GL/2 vertial plot size
Esc % # B		Enter HP-GL/2 mode
Esc % # A		Enter PCL mode
Esc Y			Display function on
Esc Z			Display function off
Esc &s # C 		End of Line Wrap
Esc *v # I		Assign color index
Esc *v # A		color component 1
Esc *v # B		color component 2
Esc *v # C		color component 3
Esc *l # W [data]	color lookup tables
Esc *v # W [data]	configure image data
Esc *m # W		download dither matrix
Esc *v # S		foreground color
Esc *t # I		gamma correction
Esc &b # M		monochrome print mode
Esc &p # I		palleter control ID
Esc &p # C		palleter control
Esc *p # P		push/pop palleter
Esc *t # J		render algorithm
Esc &p # S		select palleter
Esc *i # W [data]	set viewing illuminant
Esc *r # U		simple color
-----------------------------------------------------------------

Основные графические команды для PCL
-----------------------------------------------------------------
Esc E			initialize printer
Esc *p # X		set cursor X coordinate
Esc *p # Y		set cursor Y coordinate

Esc *t # R		set  resolution
            (All dots are square)
            (valid values is = 75,100,150,300,600...)

Esc *r 1 U		Set one plane, monochrome mode
Esc *r 3 U		Set 3 plane, color RGB mode
Esc *r -3 U		Set 3 plane, color CMY mode
Esc *r -4 U		Set 4 plane, color KCMY mode

Esc *r #  S		set image size (in pixels)
Esc *r 0  A		start draw picture from left margin of current raw
Esc *r 1  A		start draw picture from current position
Esc *b 0  M		no raster compression
Esc *b 1  M		RLE coding
Esc *b 2  M		TIFF coding
Esc *b 3  M		Delta-coding
Esc *b # V  [data]	send raw of color plane (and switch to next color plane)
                RGB:  R, G, B
                CMY:  C, M, Y
                KCMY: K(black),C,M,Y
                (Last color plane must be outputed by Esc *b#W)
Esc *b # W  [data]	send raster string  (and switch to next raster raw)
            (# = number of bytes in output)
Esc *r C		exit raster mode
-----------------------------------------------------------------

PostScript

PostScript - язык управления принтерами и фотонаборными автоматами.
Раньше широко использовался в high-end принтерах, но сейчас экономия
это забивает.

-----------------------------------------------------------------
num				abs
num1 num2			add
bool1 bool2			and
x y r ang1 ang2			arc
x y r ang1 ang2 		arcn
ax ay string 			ashow
num den				atan
cx cy char ax ay string		awitdthshow
proc				bind
int1 shift			nitshift
num				ceiling
string bool			charpath
                clip
                clippath
                closepath
                copypage
angle				cos
                currentpoint
x1 y1 x2 y2 x3 y3		curveto
num				cvi
string				cvn
string				cvt
num string radix		cvrs
num string			cvs
num1 num2			div
element				dup
elem1 elem2			eq
elem1 elem2			exch
oper				exec
                exit
base exp			exp
                fill
font				findfont
start step end { proc }		fpr
num1 num2			ge
                grestore
                gsave
num1 num2			gt
int1 int2			idiv
bool { proc }			if
bool { proc1 } {proc2} 		ifelse
width heigth bitsps matrix proc image
width heigth invert matrix proc	imagemask
a1 a2 ... ax n			index
num1 num2			le
x y				lineto
num1				ln
num1				log
{ proc }			loop
num1 num2			lt
int1 int2			mod
x y				moveto
num1 num2			mul
num1				neg
                newpath
bool1				not
bool1 bool2			or
                pop
                quit
                rand
dx1 dy1 dx2 dy2 dx3 dy3		rcurveto
count { proc } 			repeat
dx dy				rlinto
elem1 ... elemx n j		roll
num1				round
x y				scale
font scale			scalefont
string such			search
font				setfont
num				setgray
num				setlinewidth
( text )			show
                showpage
angle				sin
num				sqrt
int				string
string				stringwidth
                stroke
num1 num2			sub
num				truncate
bool1 bool2			xor
                % comment
-----------------------------------------------------------------

  Плоттер

Сейчас наибольшее распространение имеют большие "станковые" плоттеры.

TODO: HP-GL

-----------------------------------------------------------------
------------ Coordinate System -----------------
DF;				Set Default Values  of Plotter settings
IN;				Initialize plotter
IP 	p1x,p1y [,p2x,p2y];	Input
                Set coordinates of base points
                (P1 - left top, P2 - right bottom)
IR	p1x,p1y [,p2x,p2y];	Input Relative
IW 	x1,y1,x2,y2;		Set Input windows
PG;				Advance Full Page (goto next page)
RO 	angle;			Rotate coordinate system
                (Clock-overwise, degrees. valid: 90,180,270)
RP 	n;			Replot n copyes of data
SC 	Xmin,Ymax,Ymin,Ymax  	Set coordinates of P1 and P2 points
    [,type, left, bottom];	in user coordinates
----------- Drawing Primitives ----------------
AA	x,y,arc [,chord_angle];	Arc Absolute
AR	x,y,arc [,chord_angle]; Arc relative
AT	Xint,Yint,Xend,Yend	Absolute Arc Tree Point
    [,chord_angle] ;
RT	Xint,Yint,Xinc,Yinc	Relative Arc Tree Point
    [,chord_angle] ;
CI	r [,chord_angle] ;	Circle
PA	x1,y1 [,x2,y2 [,..]] ;	Plot Absolute
PR	x1,y1 [,x2,y2 [,..]] ;	Plot Relative
PD	x,y [,..] ;		Pen Down (move to point)
PU	x,y [,..] ;		Pen Up (moving to point)
PE	[flag] [value/x,y]	Polyline endcode
    [,...] ;
----------- Polygon Graphics ------------------
EA	x,y;			Edge Rectangle Absolute
ER	x,y;			Edge Rectangle Relative
EW	r,start_angle,          Edge Wedge (Sector)
    swrrp_angle [,chord_to];
EP;				Edge Polygon
                (which coordinates was previously added
                bt PM,RA,RR,WG commands)
PM	poly_def;		Polygon Mode
FP;				Fill Polygon
RA	x,y;			Fill Rectangle Absolute
RR	x,y;			Fill Rectangle relative
WG	radius, start_angle,   	Fill Wedge
    end_angle [,chord_angl];
----------- Line & Fill Attributes -------------
AC	x, y ;			Anchor Corner
FT	type [,spacing, angle];	Fill Type
LA	kind, value [,...];	Line Attributes
LT	pattern_num [,patt_len,	Line Type
    mode ] ;
PW	width [,pen] ;		Pen Width
RF	index [,width, heigth,	Raster Fill
    pen_num, ...] ;
SM	char ;			Symbol Mode
SP	pen_num ;		Select Pen
UL	index [,gap1,..,gapN];	User-Defined Line Type
WU	type;			Pen Width Unit Selection
----------- Character controls -----------------
AD	kind, value [,...];	Alternate Font Definition
CF	fill_mode [,edge_pen];	Character Fill Mode
CP	[c , l ];		Character Plot
DI	dx,dy ;			Absolute Direction
DR	dx,dy ;			Relative Direction
DT	label_terminator[,mode]; Define Label Terminator
DV	path[,line] ;		Define Variable Text Path
ES	spaces [,lines] ;	Extra space
LB	string ;		Label
LO	pos_num ;		Label origin
SA;				Select alternative font
SD	kind,val [,...] ;	Standart font definition
SI	width,heigth ;		Absolute Character Size
SL	tangent_of_angle ;	Character Slant
SR	width,heigth ;		Relative Character Size
SS;				Select standart font
TD	mode;			Transparent Data
----------- Technical Graphic extensions -------
BP	[kind,value,...] ;	Begin plot
CT	mode ;			Chord Tolerance Mode
DL	n [,count,x,y,..] ;	Download Character
EC	[n] ;			Enable cutter
FR;				Frame Advance
MC	mode ;			Merge control
MG	[message] ;		Message
MT	type ;			Media type
FNR;				Not  Ready
FOE;				Output Error
OH;				Output Hard-Clip Limits
OI;				Output Identification
OP;				Output P1 and P2
OS;				Output status
PS	[length, width] ;	Plot Size
QL	[quality] ;		Quality Level
ST	[switches];		Sort
VS	[pen_velocity,pen];	Velocity Select
----------- Palleter Extensions -----------------
CR	[black_ref_red,   	Set Color Range For Relative Color Data
     white_ref_red,
     black_ref_green,
     white_ref_green,
         black_ref_blue,
     white_ref_blue] ;
NP	n;			Number of Pens
PC	[pen,red,green,blue];	Pen Color Assignment
SV	screen_type [,options];	Screended Vectors
TR	[n];			Transparency Mode
------------ Digitizing Extensions ---------------
DC;				Digitize clear
DP;				Digitize point
OD;				Output Digitized position and Pen status
------------ Other enhancions --------------------
N fontid			Set font as secondary
-----------------------------------------------------------------

  Фотонаборные аппараты

Вывод на пленку

  3D принтер

Трехмерные принтеры выпускают уже сейчас
К сожалению пока это дорогое удовольствие

Пример Z-corporation ZPrinter 310.
Стоит ~25,000 (конец 2004 года).

Рабочий обьем 122x180x158 милиметров
Расходные материалы стоят $1-$2 за 1 кубический дюйм результата.

Разрешение 0.004 дюйма
Время объемной печати 3-4 часа (сильно зависит от размеров).

Можно печатать формы, для последущей заливки металлом.

Dimensions 3D Printer
разрешение 0.01 дюйма
203x203x305 миллиметров
Стоит ~25,000 (конец 2004 года).

Печатает быстрозастывающим пластиком.


56.5. СКАНЕР

THIS SECTION IS UNDER CONSTRUCTION

Принципиальная схема современного сканера

Для CCD - надо делать коррекцию.

  CCD

с помощью CCD сканируют, фотографируют, снимают видео и все остальное.

CCD (Charged Couple Devices)

CCD Charge Couple Devices

W.S. Boyle, G.E. Smith and G.G. Amelio, Bell Lab, 1970.

CCD is a charge transfer device, read out by shifting charge
from each pixel on the array to a serial register

Cравнение CMOS и CCD сенсоров

Интерфейсы управления сканером.

Раньше:
    Стандартизированные SCSI комманды
    HP SCL (Scanner Control Language) команды

Теперь:
    Низкоуровневые приватные интерфейсы
    (вплоть до того что выдают серию команд на перемещение головки
     в процессе сканирования)
    Поэтому сканеры такие медленные, но зато дешевые.

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

    Command                 Code
    -------------------------------
    Automatic Bkgrd         Esc*a#B
    Compression             Esc*a#C
    Download Type           Esc*a#D
    X Scale                 Esc*a#E
    Y Scale                 Esc*a#F
    Select Data Width       Esc*a#G
    Inverse Image           Esc*a#I
    B/W Dither Pattern      Esc*a#J
    Contrast Level          Esc*a#K
    Intensity Level         Esc*a#L
    Mirror Image            Esc*a#M
    Window X Ext (Dec)      Esc*a#P
    Window Y Ext (Dec)      Esc*a#Q
    X Res                   Esc*a#R
    Y Res                   Esc*a#S
    Output Data Type        Esc*a#T
    Scan speed              Esc*a#V
    Download Binary         Esc*a#W
    Window X Pos (Dec)      Esc*a#X
    Window Y Pos (Dec)      Esc*a#Y
    Reconnect level         Esc*a#Z
    Select Number of Views  Esc*f#A
    Select View             Esc*f#B
    Preload ADF             Esc*f#C
    Media type              Esc*f#D
    Coordinate system       Esc*f#E
    Pos Secondary Elem      Esc*f#F
    Light Source Test       Esc*f#L
    Window X Ext (Pix)      Esc*f#P
    Window Y Ext (Pix)      Esc*f#Q
    Scan Window (w/ID)      Esc*f0S
    Scanner Test            Esc*f#T
    Window X Pos (Pix)      Esc*f#X
    Window Y Pos (Pix)      Esc*f#Y
    Upload Binary           Esc*s#U
    Select Cal Area (Y-pos) Esc*u#A
    Byte order              Esc*u#B
    Select Cal Strip Parm.  Esc*u#C
    XPA Scan Window (w/ID)  Esc*u0D
    Speed Mode              Esc*u#E
    Set Filter              Esc*u#F
    Calibration mode        Esc*u#G
    XPA Disable/Enable      Esc*u#H
    Color Dither Pattern    Esc*u#J
    Select Tone Map         Esc*u#K
    Light Power             Esc*u#L
    Recalibrate (w/ID)      Esc*u0R
    ADF Scan Window (w/ID)  Esc*u0S
    Select Matrix Coef      Esc*u#T
    Unload Document         Esc*u0U
    Change Document         Esc*u0X
    ADF Bkgrd Feed          Esc*u0Y

Как выглядит процесс сканирования:
Дается команда вида:

    Esc * a 4 T		// select Gray scale mode
    Esc * a 8 G		// select 8-bit gray

или
    Esc * a 5 T		// select Color mode
    Esc * a 2 4 G		// select 24-bit

аналогичным образом выбираются другие параметры
например

    Esc * a 6 0 0 R		// X resolution = 600 dpi
    Esc * a 6 0 0 S		// Y resolution = 600 dpi

а в конце выдается

    Esc * f 0 S		// scan window

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

ADF - это Automatic Data Feeder - система подачи листов в сканер

3D scanners


56.6. ЗВУКОВАЯ ПОДСИСТЕМА

THIS SECTION IS UNDER CONSTRUCTION

  Ноты

Частоты нот 1й октавы (Hz)

    C	523
    D	587
    E	659
    F	699
    G	784
    A	880
    B	988

    C4	261.63
    C#4	277.18
    D4	293.66
    D#4	311.13
    E4	329.63
    F4	349.23
    F#4	369.99
    G4	392.00
    G#4	415.30
    A4	440.00
    A#4	466.16
    B4	493.88

  Музыкальные инструменты

Envelope:

Attack:

  Динамик

  Микрофон

Динамический:

Конденсаторный:

Типы микрофонов (направленность)

  Звуковая карта

  Коннекторы

THIS SECTION IS UNDER CONSTRUCTION


56.7. ПАРАЛЛЕЛЬНЫЙ ПОРТ

THIS SECTION IS UNDER CONSTRUCTION


56.8. ПОСЛЕДОВАТЕЛЬНЫЙ ПОРТ

THIS SECTION IS UNDER CONSTRUCTION

    LIBRARY ieee;
    USE ieee.Std_logic_1164.ALL;
    USE ieee.Std_logic_unsigned.ALL;

    ENTITY baudcontroller IS
        PORT(
            clk : IN std_logic;
            rst : IN std_logic;
            baud : IN std_logic_vector(0 to 2);
            clkout : OUT std_logic);
    END baudcontroller;

    ARCHITECTURE simple OF baudcontroller IS
        SIGNAL clkdiv : integer := 0;
        SIGNAL count : integer := 0;
    BEGIN
        Div: process (rst, clk)
        begin
            if rst = '0' then
                clkdiv <= 0;
                count <= 0;
            elsif rising_edge(CLK) then
                case Baud is
                    when "000" => clkdiv <= 7; -- 115200
                    when "001" => clkdiv <= 15; -- 57600
                    when "010" => clkdiv <= 23; -- 38400
                    when "011" => clkdiv <= 47; -- 19200
                    when "100" => clkdiv <= 95; -- 9600
                    when "101" => clkdiv <= 191; -- 4800
                    when "110" => clkdiv <= 383; -- 2400
                    when "111" => clkdiv <= 767; -- 1200
                    when others => clkdiv <= 7;
                end case;
            end if;
        end process;
        clockdivision: process (clk, rst)
        begin
            if rst='0' then
                clkdiv <= 0;
                count <= 0;
            elsif rising_edge(CLK) then
                count <= count + 1;
                if (count > clkdiv) then
                    clkout <= not clkout;
                    count <= 0;
                end if;
            end if;
        end process;
    END simple;

    ENTITY serialrx IS
        PORT(
            clk : IN std_logic;
            rst : IN std_logic;
            rx : IN std_logic;
            dout : OUT std_logic_vector (7 downto 0)
            );
    END serialrx;

    ARCHITECTURE simple OF serialrx IS
        type state is (idle, s0, s1, s2, s3, s4, s5, s6, s7, stop);
        signal current_state, next_state : state;
        signal databuffer : std_logic_vector(7 downto 0);
    BEGIN
        receive: process (rst, clk)
        begin
            if rst='0' then
                current_state <= idle;
                for i in 7 downto 0 loop
                    dout(i) <= '0';
                end loop;
            elsif rising_edge(CLK) then
                case current_state is
                    when idle =>
                        if rx = '0' then
                            next_state <= s0;
                        else
                            next_state <= idle;
                        end if;
                    when s0 =>
                        next_state <= s1;
                        databuffer(0) <= rx;
                    when s1 =>
                        next_state <= s2;
                        databuffer(1) <= rx;
                    when s2 =>
                        next_state <= s3;
                        databuffer(2) <= rx;
                    when s3 =>
                        next_state <= s4;
                        databuffer(3) <= rx;
                    when s4 =>
                        next_state <= s5;
                        databuffer(4) <= rx;
                    when s5 =>
                        next_state <= s6;
                        databuffer(5) <= rx;
                    when s6 =>
                        next_state <= s7;
                        databuffer(6) <= rx;
                    when s7 =>
                        next_state <= stop;
                        databuffer(7) <= rx;
                    when stop =>
                        if rx = '0' then
                            next_state <= s0;
                        else
                            next_state <= idle;
                        end if;
                        dout <= databuffer;
                end case;
                current_state <= next_state;
            end if;
        end process;
    END;

Flow control:

PnP

Modem cable

модемный кабель

нульмодемный кабель


56.9. GAME ПОРТ

THIS SECTION IS UNDER CONSTRUCTION


56.10. СЕТЕВАЯ КАРТА

THIS SECTION IS UNDER CONSTRUCTION


56.50. ДАТЧИКИ

THIS SECTION IS UNDER CONSTRUCTION

Cредняя электростанция имеет порадка 40K датчиков.
Среднее химическое производство порядка 250K.

  Интерфейс с датчиками

  Датчики

Температурные датчики
    на pn-переходах
        диод
        транзистор
    термопары
    резистивные датчики температур

Оптичексие датчики
    Фоторезистивные элементы
    Фотогальванические элементы

Датчики перемещения
    Потенциометрические резистивные преобразователи
    Резистивные тензодатчики
    Полупроводниковые датчики перемещения
    Пьезоэлектические преобразования

Датчики потока
    Конвекционные
    Механические
        с тормозящим элементом
    С трубкой Пито


56.51. УПРАВЛЕНИЕ ТИПОВЫМИ УСТРОЙСТВАМИ

THIS SECTION IS UNDER CONSTRUCTION

  Включение нагрузки

  Основы элекстродвигателей

  Шаговый электродвигатель

Другие электродвигатели


57. АНАЛОГОВЫЕ ВЫЧИСЛЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

Операционный усилитель

  Повторитель

Vo = Vin

  Инвертирующий усилитель

Vo/Vin = - R2/R1

Пример реализации усилителя x2 на Verilog-AMS

    module plant_ahdl(sigin, sigout);
        input sigin;
        output sigout;
        electrical sigin, sigout;
        analog begin
            V(sigout) <+ 2 * V(sigin);
        end
    endmodule

  Неинвертирующий усилитель

Vo/Vin = 1 + R2/R1

  Сумматор

Vo = -Rf * ( V1/R1 + V2/R2 + .. + Vn/Rn)

  Вычитающий (разностной) (дифференциальный) усилитель

Vo = R2/R1 * { (1+ R1/R2) / (1+ R3/R4) * V1 - V2 }

Vo = (V2-V1) * R2 / R1

если R1=R2 то  Vo = 2*(V2-V1)

  Интегратор

Vo = - 1/(R*C) Integral(0,t1){Vi * dt + Vic}

  Дифференциатор

Vo = - R * C * (dVi/dt)

  Компаратор

если V1 > V2, то Vo = - Vs (напряжение насыщения)
если V1 < V2, то Vo = + Vs

  Компаратор с гистерезисом

  Стабилизатор

(ограничитель амплитуды)

  Активный фильтр НЧ

  Активный фильтр ВЧ

  Полосовой фильтр

Полосовой фильтр выделяет полосу частот,
реально является комбинацией фильтров НЧ и ВЧ.

  Логарифмический усилитель

Vout= -F * ln{Vin/(Io*R)}

  Экспотенциальный усилитель

(Антилогорифмический усилитель)

Vout = Io * Rf * exp(Vin / a)

  Аналоговый умножитель

Умножитель состоит из 2х логарифмических усилителей, суммирующего
усилителя, и экспотенциального усилителя.
Antilog{Log(X) + Log(Y)} = Antilog(Log(X*Y)) = X * Y

  Выборка-Запоминание

THIS SECTION IS UNDER CONSTRUCTION


57.0. АНАЛОГОВЫЙ ТАЙМЕР

THIS SECTION IS UNDER CONSTRUCTION

555


57.1. СХЕМЫ ФАЗОВОЙ АВТОПОДСТРОЙКИ

THIS SECTION IS UNDER CONSTRUCTION

PLL (Phase Locked Loop)

Устройство PLL:

VCO (Voltage Controlled Oscillator)

Устроство VCO:


60. СХЕМОТЕХНИКА PC

В этой секции мы будем рассматривать схемотехнику PC (как наиболее
распространенной платформы).

Классическая архитектура IBM PC/AT.

Поздняя AT архитектура.
Достигла своего развития в 440BX chipsetsе.

Intel 430TX

Хабовая архитектура современных PC.

Intel 845E

Хабовая point-to-point архитектура новых PC с шиной PCI Express.

Multi I/O chip:

ICH4:


60.1. ШИНА ISA

  Наследие 8086

  Шина ISA

THIS SECTION IS UNDER CONSTRUCTION

Чтение памяти:

Запись памяти:

Чтение I/O:

Запись I/O:

Чтение DMA:

Запись DMA:


60.2. ШИНА PCI

THIS SECTION IS UNDER CONSTRUCTION

Структура:

Простое чтение:

Простая запись:

Арбитраж:


60.3.1. DMA

THIS SECTION IS UNDER CONSTRUCTION

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

Как это работало:
    Программное обеспечение настраивало регистры DMA контроллера на
    определенный блок памяти

    Когда устройству надо было передать данные оно давало на шину сигнал DRQi (DMA Request)
    (i = уникальный номер канала DMA)
    DMA контроллер это видел - и выставлял на шину адресс и другие управляющие сигналы
    а так же давал сигнал DACKi (DMA Acknowledge)
    И устройство выставляло данные на шину/читало данные с шины.

Что можно было сделать
    Установить параметры
        Адресс буфера в физической памяти
            Ранние имплементации имели ограничения что буфер не может
            пересекать границу кратную например 64K, или 128K
        Размер одной передачи
            Byte/Word/Dword
        Количество оставшихся возможных передач
        Тип операции
            Чтение/Запись
        Запустить/Остановить

    Получить состояние
        Все нормально
        DMA Overrun - зона закончилась

В общем случае DMA контроллеры устарели, сейчас устройства
просто Bus Master и сами ходят по сложным структурам памяти
содержащим указатели на буфера.


60.3.2. PIC

THIS SECTION IS UNDER CONSTRUCTION

Собственно в чем цель контроллера прерываний?

    Управление прерываниями
    Глобально
        Разрешить соответсвующий IRQ
        Запретить соответсвующий IRQ
        Узнать разрешен ли соответсвующий IRQ

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

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

        Так же возможно локальное маскирование прерываний с меньшими приоритетами
        при возникновения прерывания с большим приоритетом.

    Режим прерываний
        edge-triggered
        level-triggered
            позволяет расшаривать прерывания
    Вектор прерывания для процессора

Процессору передается:
        PIC to Processor:  PIRQ, Vector
        Processor to PIC:  PIRQACK

Иногда функциональность PIC полностью или частично включена
в микропроцессор.

Для мультипроцессорных систем (или систем с несколькими ядрами)
    Распределение прерываний по процессорам

Типичные модели работы:
    Все прерывания на одном процессоре
        На этапе загрузки это ставиться всегда
    Некоторые прерывания на конкретном процессоре или группе процессоров
        Удобно когда обработчик сидит на одном и том же процессоре
        (во первых данные могут жить в cache).
    Некоторые прерывания на всех процессорах
        Алгоритмы распределения:
            Round robin
    Межпроцессорные прерывания
        Как правило используется OS для scheduling
            Могут быть и переодическими
        Используются для инициализации вторичных процессов
        Могут быть broadcast
            включая процессор который посылал
            исключая процессор который посылал

В этом случае на межпроцессорную шину кроме вектора прерывания
еще передается и его тип (обычное или сброс процессора) а так же
номер процессора который является приемником.

Что бы разделять прерывания между устройствами надо что бы запрос IRQ шел по
уровню, а не по фронту.

Устройство должно иметь бит состояния - который показывает, что оно требует IRQ
(может быть неколько битов - которые показывают причину IRQ),
и бит (биты) которые позволяют сбрасывать запрос IRQ у устройства.

  8259A PIC

По фронту	(ISA)
По уровню	(PCI)  могут разделять одну линию IRQ

8259A

  APIC

Local APIC - в процессорах
I/O   APIC - занимается внешними прерываниями и их рутингом между процессорами


60.3.3. PIT

THIS SECTION IS UNDER CONSTRUCTION

В чем сущность программироваемого интервального таймера?

К таймеру подключен источник синхронизации фиксированной частоты.

У таймера есть каналы. Каждый канал имеет вывод.
У канала есть регистры управления
        Начальный счетчик
        Текущий счетчик
        Режим работы
            Форма выходного сигнала
            Переинициализация - надо ли считать только один раз (one-shot mode)
                        или по окончанию счета снова его запустить
                        загрузив текущий счетчик значением начального
                        (pereodical mode)

Зачем используется интервальный таймер.

    Генерация переодических прерываний
        выход таймера подсоединяют к входу контроллера прерываний
    Реализация микрозадержек
        например драйверу надо 10ms пока устройство не придет в себя
        драйвер считает этот интервал используя таймер
    Генерация сигналов заданной формы
        например для управления оборудованием
            шаговый двигатель например
        или генерация звука заданной частоты

Классические таймеры имеют частоту тактирования и соответсвенно разрешающую
способность порядка 1MHz, и 3-5 каналов.

Но наметилась тенденция к включение в оборудование High Performance Timers
имеющих частоту порядка 10MHz, которые имеют большое число каналов - порядка 32.
Некоторые каналы могут считать и 64-битовые числа.
Кроме того практически все каналы разводятся на прерывания, что позволяет
операционной системе гораздо более эффективно управлять scheduling.
Есть возможность управления формой вывода (Edge-triggered, Level-triggered)

Например в PC HPET заменяет прерывания по таймеру, RTL и дает доп возможности

  8254 PIT

  HPET


60.3.4. RTC

THIS SECTION IS UNDER CONSTRUCTION

RTC (Real Time Clock) - устройство которое считает абсолютное (а не интервальное)
время. RTC иммет двойное питание - от сети и от батарейки, в результате чего оно
работает даже тогда когда компьютер выключен.

Если батарейка разрядилась то при старте компьютера мы увидим начальное время для BIOS.

Поскольку RTC единственно всегда работающее устройство, то в него встраивают некоторое
количество статической памяти (CMOS RAM) в которой BIOS хранит свою конфигурацию.

Точность RTC не сравнима даже с нормальными наручными часами. Как правило за год RTC
врет на несколько минут, а то и десятков.

К RTC подключен генератор дающий сигналы заданной частоты.

RTC занимается делением этого сигнала.
Как это выглядит - есть базовый счетчик который считает такты,
как только количество тактов доходит до секунды RTC инкрементирует регистр секунд
итд.

Во время обновления выставляется флаг в регистре статуса, что означает что идет
обновление и время - неправильное.

RTC имеет возможность встраивать будильник. Как только будет достигнуто значение
времени соответсвующее будильнику - будет вызвано прерывание.

Так же как правило RTL может так же давать переодическое прерывание - как правило раз в
секунду или раз в минуту.

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


60.3.5. FDC

THIS SECTION IS UNDER CONSTRUCTION

FDC
    Redice Write		C	(For DD/QD)
    Index			D
    Motor on A		C
    Drive Select 1		C
    Drive Select 0		C
    Motor on B		C
    Direction		C
    Step			C
    Write Data		C
    Write Gate		C
    Track 0			D
    Write Protect		D
    Read Data		D
    Side 1			C
    Disk Changed		D       (HD,ED)

    Step
    Direction  (0 to center of disk, increment track #)

    Work:
        Motor on
        Drive Select

    Seek:
        Direction
        Step
        Step
        Step
        (Wait while head is stabialized)

Похожий интерфейс у старых контроллоеров жестких дисков ST-506/412:

ST-506/412

    Signal			Controller/Disk
    -HD SLCT3		C
    -HD SLCT2               C
    -Write Gate             C	(Write enable)
    -Seek Complete		D
    -Track0			D
    -Write Fault		D
    -HD SLCT 0		C
    -HD SLCT 1              C
    -Index			D
    -Ready			D
    -Step			C
    -DRV SLCT 0		C
    -DRV SLCT 1		C
    -Direction In		C
    -DRV SLCTD		D
    +MFM Write		C
    -MFM Write		C
    +MFM Read		D
    -MFM Read		D


60.3.6. USB

THIS SECTION IS UNDER CONSTRUCTION


60.3.7. КОНТРОЛЛЕР ПАМЯТИ

THIS SECTION IS UNDER CONSTRUCTION

Как мы помним динамическая память работает как матрица (CAS/RAS). А адресса памяти на
шине являются просто числом.

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

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

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


61. СИЛОВАЯ ЭЛЕКТРОННИКА

THIS SECTION IS UNDER CONSTRUCTION

  Трехфазное питание

  Трансформаторы

Трехфазные трансформаторы

  Выпрямление

  Стабилитроны

  Блоки питания

  Батареи и аккумуляторы

  Батарейки

Alkaline

Zn + 2MnO2 -> ZnO + Mn2O3

  Аккумуляторы

NiCd
    Cd + 2NiOOH + 2 H2O -> Cd(OH)2 + 2Ni(OH)2
        Cd(OH)2 + 2e -> Cd + 2OH-
        Ni(OH)2 + OH- -> NiOOH + H2O + e

Li-Ion
    LixC6 + Li(i-x)CoO2 -> LiCoO2 + C6

Fuel cell methanol
    CH3OH + 3/2 O2 -> CO2 + 2H2O

  UPS


70.1. ОСНОВНЫЕ УПРАВЛЯЮЩИЕ КОНСТРУКЦИИ

THIS SECTION IS UNDER CONSTRUCTION

В этой секции мы  рассматотрим основные алгоритмические концепции
И их типичную реализацию на ассемблере.

  Действие

 ----------------------------------------
    действие
 ----------------------------------------

 ----------------------------------------
    ; action
 ----------------------------------------

  if

 ---------------------------------------
    if (условие) then
    {
        действие
    }
 ---------------------------------------

 ----------------------------------------
    ; condition
    JUMPcond	@1
    JMP		@2
@1:
    ; action
@2:
 ----------------------------------------

  if..else

 ---------------------------------------
    if (условие) then
    {
        действие1
    } else {
        действие2
    }
 ---------------------------------------

 ----------------------------------------
    ; condition
    JUMPnot_cond	@1
    ; action 1
    JMP		@2
@1:
    ; action 2
@2:
 ----------------------------------------

  while

 ----------------------------------------
    while(условие)
    {
        действие
    }
 ----------------------------------------

 ----------------------------------------
@1:
    ; condition
    JUMPnot_cond	@2
    ; action
    JMP		@1
@2:
 ----------------------------------------

  until

 ----------------------------------------
    until (условие)
    {
        действие
    }
 ----------------------------------------

 ----------------------------------------
@1:
    ; condition
    JUMPcond	@2
    ; action
    JMP		@1
@2:
 ----------------------------------------

  repeat..until

 ----------------------------------------
    repeat
    {
        действие
    } until (условие)
 ----------------------------------------

 ----------------------------------------
@1:
    ; action
    ; condition
    JMPcond		@1
@2:
 ----------------------------------------

  do..while

 ----------------------------------------
    do
    {
        действие
    } while (условие)
 ----------------------------------------

 ----------------------------------------
@1:
    ; action
    ; condition
    JMPnot_cond	@1
@2:
 ----------------------------------------

TODO: Добавить сюда
    case
    подпрограммы
    сопрограммы
        простые сопрограммы
        итераторы
    исключения


70.1.1. ПАРАЛЕЛЬНЫЕ КОНСТРУКЦИИ

THIS SECTION IS UNDER CONSTRUCTION

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

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

Основу паралельных конструкций составляет барьер:

                | одна нить
                |
            V
    ==================  точка распаралеливания
      |   |   |   |
      |   |   |   |
      паралельное выполнение
          |   |   |   |
          V   V   V   V
    =================== барьер
        |
        V

Паралельное выполнение кончается у барьера.
Варианты поведения барьера:

        Барьер
        /   \
        Ждущий  Неждущий

Неждущий 	барьер не ждет окончания выполнения всех нитей
        а пропускает первые дошедшие N нитей дальше (как правило N=1)
Ждущий		барьер ждет пока все нити дойдут до барьера
        затем пропускает первые N нитей дальше

Смешанный	барьер ждет пока первые M нитей не достигнуть барьера
        затем пропускает первые N нитей дальше

  Доступ к данным

CRCW	Concurent Read Concurent Write
CREW	Concurent Read Exclusive Write
ERCW	Exclusive Read Concurent Write
EREW	Exclusive Read Exclusive Write

  Простая паралелизация

  ---------------------------
    PAR
    {
        A;
        B;
        C;
        D;
        E;
        F;
    }
  ---------------------------

Все подоператоры выполняются паралельно - кто первый взял тот и выполнил.
Пример выполнения на 3 нитях:

    -------------------------
    # нити	  0   1   2
    - - - - - - - - - - - - -
    задачи    A   B   D
              C       F
              E
    -------------------------

  Паралелизация с секциями

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

  ---------------------------
    PAR
    {
        SEQ
        {
            A1
            A2
        }
        SEQ
        {
            B1
            B2
            B3
        }
        SEQ
        {
            C1
        }
        SEQ
        {
            D1
            D2
        }
    }
  ---------------------------

Пример выполнения на 3 нитях:
    -------------------------
    # нити	  0    1    2
    - - - - - - - - - - - - -
    задачи    A1   B1   C1
              A2   B2
                   B3
                   D1
               D2
    -------------------------

  Паралелизация циклов

Итерации для цикла выполняются паралельно
  ---------------------------
    PARFOR	i = 1 TO 5
    {
        A(i)
    }
  ---------------------------
как правило подразумевается
  ---------------------------
    PARFOR i = 1 TO 5
    {
        SEQ
        {
            A(i)
        }
    }
  ---------------------------

Пример выполнения на 3 нитях:
    -------------------------
    # нити	  0    1    2
    - - - - - - - - - - - - -
    задачи    A(1)  A(3)  A(5)
          A(2)  A(4)
    -------------------------

Паралелизация внутри цикла:

  ---------------------------
    PARFOR  i = 1 TO 2
    {
        PAR
        {
            A(i)
            B(i)
        }
    }
  ---------------------------
это то же самое что
  ---------------------------
    PAR
    {
        A(1)
        B(1)
        A(2)
        B(2)
    }
  ---------------------------
то есть запросто

Паралелизация вложенных циклов
  ----------------------------
    PARFOR i = 1 TO 2
    {
        PARFOR j = 1 TO 2
        {
            A(i,j)
        }
    }
  ----------------------------
тоже самое что
  ----------------------------
    PAR
    {
        A(1,1)
        A(1,2)
        A(2,1)
        A(2,2)
    }
  ----------------------------

  Паралелизация с атомарными операциями

  -----------------------------
    PARFOR i = 1 TO 8
    {
        SEQ
        {
            A
            ATOMIC
            {
                B
            }
            C
        }
    }
  -----------------------------

Секция ATOMIC означает что в ней может работать только одна нить одновременно
Пример выполнения операций на 3х нитях:
    -------------------------------------------------------
    # нити	  0     1     2     3
    - - - - - - - - - - - - - - - - -    выбран  очередь
    задачи    A(1)  A(3)  A(5)  A(7)	--	--
          B(1)  wait  wait  wait	0	2 1 3
          C(1)  wait  B(5)  wait	2	1 3
          A(2)  B(3)  C(5)  wait	1	3
          wait  C(3)  A(6)  B(7)	3	0
          B(2)  A(4)  wait  C(7)	0	2
          C(2)  wait  B(6)  A(8)	2	1
            B(4)  C(6)  wait	1	3
            C(4)	    B(8)	3	--
                    C(8)	--	--
    -------------------------------------------------------

Другой вариант разрешает работать в секции только master thread

OCCAM-II

    SEQ
       ....

паралельный IF:
    IF
       cond1
          process1
       cond2
          process2
       cond3
              proces3

    PAR
       WHILE TRUE
         SEQ
           ....
           WHILE TRUE
         SEQ
               ....

Циклы:
    SEQ I = 0 TO 2
          SEQ
        ....

    PAR I = 1 TO 2       тоже самое что	PAR
      PAR                                      P(1)
          P(I)                                 Q(1)
          Q(I)			           P(2)
                                               Q(2)

Переменные могут быть shared могут быть local

Каналы связи между паралельными процессами:

    CHAN OF BYTE keyboard
    CHAN OF BYTE screen
    CHAN OF INT  term_in, term_out
    PAR
        editor(term_in,term_out)
        keyboard_handler(keyboard,term_in)
        screen_handler(term_out, screen)

Очень все напоминает HDLs.

Критическая секция

    --------------
    P(mutex)
        Тело критической секции
    V(mutex)
    ---------------

Барьерная синхронизация

Возможные варианты синхронизации
    Разделяемый счетчик
    Древовидная структура
    Барьер-бабочка

Идейная часть

        1 2
        +-+

    process1		process2
    {			{
        ...             	....
        V(arrive1)		V(arrive2)
        P(arrive2)		P(arrive1)
    }			}

Древовидная структура
        1 2 3 4 5 6 7 8
        +-+ +-+ +-+ +-+
         +---+   +---+
           +-------+

Барьер-Бабочка
        1 2 3 4 5 6 7 8
           L1   +-+ +-+ +-+ +-+

       L2   +---+   +---+
          +---+   +---+

       L3   +-------+
                  +-------+
                    +-------+
                       +------+

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


70.2. ОСНОВНЫЕ СТРУКТУРЫ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

    o Целые типы и Endian
    o Типы с плавающей точкой
    o Структуры и выравнивание данных
    o Биты и битовые поля
    o Представление символов
    o Указатели и модели памяти
    o Массивы
    o Строки
    o Коллекции


70.2.1. ЦЕЛЫЕ ТИПЫ И ENDIAN

THIS SECTION IS UNDER CONSTRUCTION

  Целые числа

Свойства целых чисел:
    Формат представления
        Зависит от комьютера
        Но сейчас практически все дополнительный код (дополнение до 2)
    Размер
    Signed/Unsigned
    Endian

    8S	-128..127
    8U	0..255

    16S	-32 768..32 767
    16U	0..65 535

    32S	-2 147 483 648..2 147 483 647
    32U	0..4 294 967 295

    64S	-9 223 372 036 854 775 808..9 223 372 036 854 775 807
    64U	0..18 446 744 073 709 551 615

О форматах представления чисел можно прочитать в секции:
3.12. ПРЕДСТАВЛЕНИЕ ОТРИЦАТЕЛЬНЫХ ЧИСЕЛ В СЧ С НАТУРАЛЬНЫМ ОСНОВАНИЕМ

Об операциях над целыми типами данных, которые слишком большие, что бы CPU
их обрабатывал можно прочитать в секции:
41.3. АРИФМЕТИКА ДВОЙНОЙ И МНОГОКРАТНОЙ ТОЧНОСТИ

  Рефлексия для целочисленных типов

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

Понятно, что sizeof() - это самый простой случай.

// limits.h

#define	CHAR_BIT	8	// количество бит в char

#define	CHAR_MAX	127
#define	CHAR_MIN        -127
#define	SCHAR_MAX       127
#define	SCHAR_MIN       -127
#define	UCHAR_MAX       255

#define	SHRT_MIN 	-32767  // типовой пример для 2х байт short
#define	SHRT_MAX	32767
#define	USHRT_MAX	65535

#define	INT_MIN		-2147483647
#define	INT_MAX		2147483647
#define	UINT_MAX	4294967295U

#define	LONG_MAX        -2147483647L
#define	LONG_MIN	2147483647L
#define	ULONG_MAX	4294967295UL

#define	LLONG_MAX	-9223372036854775807LL
#define	LLONG_MIN	9223372036854775807LL
#define	ULLONG_MAX      18446744073709551615ULL

Прочитайте еще раздел 70.2.1.1. ТИПЫ С ПЛАВАЮЩЕЙ ТОЧКОЙ.
Там описан C++ шаблон numeric_limits.

  Уточнение требований

Собственно обычно требуется:
    Точное соответсвие разрядности
    Не меньше разрядность, но что бы было удобно платформе
        потому что точной разрядности может и не быть.
    Не меньше разрядность, но что бы было быстрее платформе
    Разрядность на меньше чем у указателя

Стандарт C гарантирует только:

sizeof(char) = 1
sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Кстати размер wchar_t тоже зависит от платформы.
Например на Windows он 16 бит, а на Mac OS X  32 бит (и хотя у GCC есть ключ что его
надо трактовать как 16, но стандарные библиотеки ориентированы на 32).

C99
// stdint.h

Четко размер:
    int8_t		uint8_t
    int16_t		uint16_t
    int32_t		uint32_t
    int64_t		uint64_t

Как минимум размер:
    int_least8_t	uint_least8_t
    int_least16_t	uint_least16_t
    int_least32_t	uint_least32_t
    int_least64_t	uint_least64_t

Наиболее быстрый тип с разрядностью не меньше чем:
    int_fast8_t	uint_fast8_t
    int_fast16_t	uint_fast16_t
    int_fast32_t	uint_fast32_t
    int_fast64_t	uint_fast64_t

Целый тип максимального размера:
    intmax_t	uintmax_t

Целый тип который может в себе хранить значения указателей:
    intptr_t	uintptr_t

Модели типов данных

    char	short	int	long	long long	void*
L32	8	16	16	32	--		16
LP32	8	16	16	32	--		32
ILP32	8	16	32	32	64		32
P64	8	16	32	32	64		64
LP64	8	16	32	64	64		64

  Пример расчета типов фиксированного размера через шаблоны

CODE

template <unsigned n> struct Int0
{
    typedef typename Int0<n + 1>::Type Type;
};

#define Int_Define(T, p) \
template <> struct Int0<sizeof(T) * 16 + p> { \
typedef T Type; \
};

// Lower number has priority for same sized types
Int_Define(signed char, 0)
Int_Define(short, 1)
Int_Define(int, 2)
Int_Define(long, 3)
Int_Define(long long, 4)

template <unsigned n> struct Int
{
typedef typename Int0<(n + 8 - 1) / 8 * 16>::Type Type;
};

typedef Int<8>::Type int8_t;
typedef Int<16>::Type int16_t;
typedef Int<32>::Type int32_t;
typedef Int<64>::Type int64_t;

  C RTL для целочисленных типов

int		abs(int x);
long		labs(long x);
long long       llabs(long long x);

int	abs(int x)
{
    return (x < 0)? -x : x;
}

Часто требуется получить и результат от деления и остаток.
И в большинстве случаев при делении процессор вычисляет сразу
и то и другое.
Но в языке C/C++ нет операции чтобы сделать это сразу,
поэтому используются библиотечные функции.

div_t	div(int numer, int denom);
ldiv_t	ldiv(long numer, long denom);
lldiv_t lldiv(long long numer, long long denom);

typedef struct div_t
{
    int	quot;
    int	rem;
} div_t;

typedef struct ldiv_t
{
    long	quot;
    long	rem;
} ldiv_t;

typedef struct lldiv_t
{
    long long quot;
    long long rem;
} lldiv_t;

intmax_t   imaxabs(intmax_t arg);

imaxdiv_t  imaxdiv(intmax_t numer, intmax_t denom);

typedef struct imaxdiv_t
{
    intmax_t  quot;
    intmax_t  rem;
} imaxdiv_t;

  Endian у целых чисел

            Integer
            / 	\
        Big-Endian	Little-Endian

Byte sexuality.

Big endian:

Little endian:

     BIG-ENDIAN				LITTLE-ENDIAN

   word  low -----> high 		word	 low  ---->  high
   addr   byte address			addr      byte address
    +---+---+---+---+			+---+---+---+---+
   0	| 0 | 1 | 2 | 3 |		0	| 3 | 2 | 1 | 0 |
    +---+---+---+---+			+---+---+---+---+
   1	| 4 | 5 | 6 | 7 |		1	| 7 | 6 | 5 | 4 |
    +---+---+---+---+			+---+---+---+---+
    |		|			|		|

    Motorolla MC68XXX, 		Zilog z80, Intel x86, Itanium
    PowerPC, Alpha, SPARC
    (Network byte order)

    WORD	1234h:	     		WORD	1234h:
        A	12h			A	34h
        A+1	34h			A+1	12h

    DWORD	12345678h		DWORD	12345678h
        A	12h			A	78h
        A+1	34h			A+1	56h
        A+2	56h			A+2	34h
        A+3	78h			A+3	12h

    Удобно смотреть dump		Удобно преобразовывать типы

Еще существует Cross-Endian (старые DEC PDP-11 и некоторые старые VAX в режиме
совместимости с PDP-11).
К счастью он не бывает 64-бит, только 32-бит:

       ADDR    0    1   2	 3	DWORD value = 12345678h
              +----+----+----+----+
Big-endian      | 12 | 34 | 56 | 78 |	4321  	Motorola
        +----+----+----+----+
Little-endian   | 78 | 56 | 32 | 12 |	1234	Intel
        +----+----+----+----+
Cross-endian	| 34 | 12 | 78 | 56 |	3412	PDP-11
        +----+----+----+----+

Определение Endian на Runtime

// Check only for Big and Little endian, not for cross endian
bool islittleend()
{
    static long l = 0x12345678;
    volatile char* c = (char*) &l;
    if (*c == 0x78) return true;
    return	false;
}

Работа с endian числами.

Большинство процессоров работают с какимто одним endian
(например: Intel, PowerPC, Alpha).
Но есть процессоры, которые могут работать с числами в любом endian например MIPS.
(Скажем в IRIX 6.5 на SGI Octane есть 4 основных targets для приложений:
    32-bit Big endian
    32-bit Little endian
    64-bit Big endian
    64-bit Little endian

В некоторых микропроцессорах есть команды которые позволяют менять
endian. Например для x86:

    XCHG 	ah,al	; 16
    BSWAP   eax	; 32
    BSWAP	rax	; 64 - CHECK if exist

Примитивы для смены endian

int16 int16_change_endian(int16 v)
{
    return (v >> 8) | (v << 8);
}

int32 int32_change_endian(int32 v)
{
    return int16_change_endian(v >> 16) | (((int32) int16_change_endian(v & 0xffff)) << 16);
}

//int64_change_endian	// aналогично

Есть стандартные функции для сокетов, но они преобразуют только для short и long
(причем имееются в виду размеры 16 и 32).
Network - это естественно big-endian format

u_short  ntohs(u_short  netshort);
u_long   ntohl(u_long   netlong);
u_short  htons(u_short  hostshort);
u_long	 htonl(u_long   hostlong);

Макросы для конвертации в жестко заданный endian

#ifdef BIG_ENDIAN
#define	int32_to_BE(x)   (x)
#define	int32_from_BE(x) (x)
#else
#define	int32_to_BE(x)   int32_change_endian
#define int32_from_BE(x) int32_change_endian
#endif

Функции для конвертации в переменный endian

int32 int32_to_end(int32 x, int endian)
{
    return (endian == nativeentian)? x : int32_change_endian(x);
}

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

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

struct	be_ushort
{
    unsigned short v;

    operator unsigned short()
    {
        return	int16_from_BE(v);
    }

    operator=(unsigned short nv)
    {
        v = int16_to_BE(nv);
    }
    // другие конвертации отпускаем
};

  Endian и cимволы

Символьные типы - это тоже целочисленные типы.
И как целочисленные типы - подвержены проблеме endian

Даже UNICODE бывает обоих форм.

    'A' => ASCII 41h  => UNICODE 0041h

    Big-Endian		Little-Endian
    00h			41h
    41h			00h

  Endian и Битовые поля

Еще проблемы с битовыми полями:

В ЯВУ распределение битовых полей начинается от бита 0 и идет в сторону
старших битов.

         0		      31  BIT
        +-----+-----+-----+-----+
Big-endian	|BF| -- >               |       Motorola
        +-----+-----+-----+-----+
           3     2     1     0    BYTE

         31		       0  BIT
        +-----+-----+-----+-----+
Little-endian	|               < -- |BF| 	Intel
        +-----+-----+-----+-----+
           3     2     1     0    BYTE

Пример заголовка для первого байта IPv4 пакета:
(Типичное значение этого байта 45h (версия = 4, длинна заголовка = 5 DWORDs))
-------------------------------------------
    struct	IPv4Byte1
    {
    #ifdef	BIG_ENDIAN
        unsigned	version:4;
        unsigned	length:4;
    #else
        // Little-endian
        unsigned	length:4
        unsigned	version:4
    #endif;
    }
-------------------------------------------

------------------------------------------
struct	a
{
    unsigned b:12;		// bits 0..11
    unsigned c:4;		// bits 12..15
};

main()
{
        struct	a  aa;
    unsigned short *  pc;
    aa.c = 0xf;
    aa.b = 0;
    pc = (unsigned short *) &aa;
    printf("Bitfield byte = %x\n",(int) (*pc));
}
--------------------------------------------

Result is on x86:   F000	Little-endian
Result is on SPARC: 000F	Big-endian


70.2.1.1. ТИПЫ С ПЛАВАЮЩЕЙ ТОЧКОЙ

Основные свойства FP чисел:
    формат представления
        зависит от компьютера
            но сейчас в основном IEEE 754
    Размер
    Endian
    Особенности представление NaN

О форматах чисел с плавающей точкой можно прочитать в секции
40.1. ЧИСЛА С ПЛАВАЮЩЕЙ ТОЧКОЙ

Собственно FP числа тоже подвержены endian.
Об этом тоже можно прочитать в секции 40.1.

// C
double	     fabs(double x);
float	     fabsf(float x);		// C99
long double  fabsl(long double x);	// C99

double	     acos(double x);
float	     acosf(float x);		// C99
long double  acosl(long double x);	// C99

double	     asin(double x);
float	     asinf(float x);		// C99
long double  asinl(long double x);	// C99

double	     atan(double x);
float	     atanf(float x);		// C99
long double  atanl(long double x);	// C99

double	     atan2(double y, double x);
float	     atan2f(float y, float x);             // C99
long double  atan2l(long double y, long double x); // C99

double	     cbrt(double x);		// C99
float	     cbrtf(float x);		// C99
long double  cbrtl(long double x);	// C99

double	     cos(double x);
float	     cosf(float x);      	// C99
long double  cosl(long double x);	// C99

double	     cosh(double x);
float	     coshf(float x);		// C99
long double  coshl(long double x);	// C99

double	     exp(double x);
float	     expf(float x);		// C99
long double  expl(long double x);	// C99

double	     exp2(double x);		// C99
float	     exp2f(float x);		// C99
long double  exp2l(long double x);	// C99

double	     exp2m1(double x);		// C99
float	     exp2m1f(float x);		// C99
long double  exp2m1l(long double x);	// C99

double       log(double x);
float	     logf(float x);      	// C99
long double  logl(long double x);	// C99

double	     log10(double x);
float	     log10f(float x);      	// C99
long double  log10l(long double x);	// C99

double	     log2(double x);		// C99
float	     log2f(float x);		// C99
long double  log2l(long double x);	// C99

double	     logp1(double x);		// C99
float	     logp1f(float x);		// C99
long double  logp1l(long double x);	// C99

double	     pow(double x, double y);
float	     powf(float x, float y);	         // C99
long double  powl(long double x, long double y); // C99

double	     sin(double x);
float	     sinf(float x);      	// C99
long double  sinl(long double x);	// C99

double	     sinh(double x);
float	     sinhf(float x);		// C99
long double  sinhl(long double x);	// C99

double	     sqrt(double x);
float	     sqrtf(float x);		// C99
long double  sqrtl(long double x);	// C99

double	     tan(double x);
float	     tanf(float x);		// C99
long double  tanl(long double x);	// C99

double	     tanh(double x);
float	     tanhf(float x);		// C99
long double  tanhl(long double x);	// C99

double	     hypot(double x, double y);	           // C99
float	     hypotf(float x, float y);	           // C99
long double  hypotl(long double x, long double y); // C99

double	     erf(double x);		// C99
float	     erff(float x);		// C99
long double  erfl(long double x);	// C99

double	     erfc(double x);		// C99
float	     erfcf(float x);		// C99
long double  erfcl(long double x);	// C99

double	     gamma(double x);		// C99
float	     gammaf(float x);		// C99
long double  gammal(long double x);	// C99

double	     lgamma(double x);		// C99
float	     lgammaf(float x);		// C99
long double  lgammal(long double x);	// C99

double	     tgamma(double x);		// C99
float	     tgammaf(float x);		// C99
long double  tgammal(long double x);	// C99

double	     fdim(double x, double y);  	  // C99
float	     fdimf(float x, float y);   	  // C99
long double  fdiml(long double x, long double y); // C99

double	     copysign(double x, double y);	      // C99
float	     copysignf(float x, float y);	      // C99
long double  copysignl(long double x, long double y); // C99

double	     fma(double x, double y, double z);			// C99
float	     fmaf(float x, float y, float z);			// C99
long double  fmal(long double x, long double y, long double z); // C99

double	     fmax(double x, double y);		  // C99
float	     fmaxf(float  x, float y);		  // C99
long double  fmaxl(long double x, long double y); // C99

double	     fmin(double x, double y);		  // C99
float	     fminf(float  x, float y);		  // C99
long double  fminl(long double x, long double y); // C99

Округления и преобразования к целому:

double	ceil(double x);
float	ceilf(float x);
double	floor(double x);
float	floorf(float x);

double	     fmod(double x, double y);
float	     fmodf(float x, float y);		    // C99
long double  fmodl(long double x, long double y);   // C99

double	modf(double x, double* intptr);	// split FP to fractional and integer part
float	modff(float x, float*  intptr);

double	    trunc(double x);		// C99

?	    rint(double x);		// C99
?	    round(double x);		// C99

long        lrint(double x); 		// C99
long	    lround(double x);		// C99

long long   llrint(double x);		// C99
long long   llround(double x);		// C99

double      nearbyint(double x);			// C99
double	    nextafter(double x, double towards);        // C99
double	    nexttoward(double x, double towards);	// C99

double	    remainder(double x, double y);	   // C99
double	    remquo(double x, double y, int* quo);  // C99

Манипулирования над частями

double	frexp(double x, int* expptr);	// get mantissa and exponent
double	ldexp(double x, int exp);	// compute number from mantissa and exponent

int	signbit(double x);		// C99

double	nan(char* pattern);		// C99

int	_finite(double x);
int	_isnan(double x);
double  _scalb(double x, long exp);	// Scale by power of 2

int     fpclassify(double x);

int	isfin(double x);		// C99
int	isinf(double x);		// C99
int	isnan(double x);		// C99
int	isnormal(double x);		// C99
int	isunordered(double x);		// C99

Естественно в C++ перегружаются функции:

// C++
double	     sin(double x);
float	     sin(float  x);
long double  sin(long double x);

и так по всей библиотеке.

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

1) FPU отсутствует, вычисления проводяться с помощью целых чисел.
   подпрограммы эмулируют работу FP

2) FPU присудствует но способен выполнять только примитивные
   команды:  +, -, *, /, sqrt

3) FPU присутствует и способен выполнять транцедентальные команды.

  Рефлексия для FP типов

THIS SECTION IS UNDER CONSTRUCTION

FLT_RADIX - основание системы счисления используемой для представления FP
        на данной платформе

FLT_MIN		DBL_MIN		LDBL_MIN	  минимальное положительное число
FLT_MAX		DBL_MAX		LDBL_MAX	  максимальное положительное число
FLT_MIN_EXP	DBL_MIN_EXP	LDBL_MIN_EXP	  минимальная экспонента в FLT_RADIX
FLT_MAX_EXP	DBL_MAX_EXP	LDBL_MAX_EXP	  максимальная экспонента в FLT_RADIX
FLT_MIN_10_EXP	DBL_MIN_10_EXP	LDBL_MIN_10_EXP	  десятичная экспонента минимального +числа
FLT_MAX_10_EXP	DBL_MAX_10_EXP	LDBL_MAX_10_EXP	  десятичная экспонента максимального +числа
FLT_DIG		DBL_DIG		LDBL_DIG	  Число десятичных цифр которое можно хранить
FLT_MANT_DIG	DBL_MANT_DIG	LDBL_MANT_DIG     Число бит в мантисе в FLT_RAIDX
FLT_EPSILON	DBL_EPSILON	LDBL_EPSILON	  разница между 1 и мин числом большим 1

// C float.h

#define FLT_RADIX 	2

// float 4-bytes IEEE754:

#define FLT_MIN 	1.175494351e-38F
#define FLT_MAX 	3.402823466e+38F
#define FLT_MIN_EXP     (-125)
#define FLT_MAX_EXP 	128
#define FLT_MIN_10_EXP  (-37)
#define FLT_MAX_10_EXP 	38
#define FLT_DIG 	6
#define FLT_MANT_DIG 	24
#define FLT_EPSILON 	1.192092896e-07F

// double 8-bytes IEEE754:

#define DBL_MIN 	2.2250738585072014e-308
#define DBL_MAX 	1.7976931348623158e+308
#define DBL_MIN_EXP 	(-1021)
#define DBL_MAX_EXP 	1024
#define DBL_MIN_10_EXP 	(-307)
#define DBL_MAX_10_EXP 	308
#define DBL_DIG 	15
#define DBL_MANT_DIG 	53
#define DBL_EPSILON 	2.2204460492503131e-016

  Рефлексия для целочисленных и FP типов

В С++ есть trait-шаблон numeric_limits<>, который перегружен для всех
примитивных типов данных.
С помощью его можно получить необходимые свойства для типов данных.

// C++ <limits>

typedef enum
{
    denorm_indeterminate = -1,
    denorm_absent = 0,
    denorm_present = 1
} float_denorm_style;

typedef enum
{
    round_indeterminate = -1,
    round_toward_zero = 0,
    round_to_nearest = 1,
    round_toward_infinity = 2,
    round_toward_neg_infinity = 3
} float_round_style;

template<class T> class numeric_limits
{
public:
    static const bool is_specialized = false;

    static const bool has_denorm_loss = false;
    static const bool has_infinity    = false;
    static const bool has_quiet_NaN   = false;
    static const bool has_signaling_NaN = false;
    static const bool is_bounded = false;
    static const bool is_exact = false;
    static const bool is_iec559 = false;
    static const bool is_integer = false;
    static const bool is_modulo = false;
    static const bool is_signed = false;
    static const bool tinytess_before = false;
    static const bool traps = false;
    static const float_round_style round_style = round_toward_zero;
    static const float_denorm_style has_denorm = denorm_absent;
    static const int digits = 0;
    static const int digits10 = 0;
    static const int max_exponent = 0;
    static const int max_exponent10 = 0;
    static const int min_exponent = 0;
    static const int min_exponent10 = 0;
    static const int radix = 0;

    static T  min() throw();
    static T  max() throw();
    static T  epsilon() throw();
    static T  round_error() throw();
    static T  denorm_min() throw();
    static T  infinity() throw();
    static T  quiet_NaN() throw();
    static T  signaling_NaN() throw();
};

  Управление операциями с плавающей точкой

Свойства FP окружения
    Режим округления
        получить
        установить
    FP Exceptions
        разрешить
        запретить
        узнать текущее состояние запрещения
        узнать произошло ли FP exception

В С99 наконец-то это стандартизовали.
До этого приходилось пользоваться платформо-зависимым кодом.

// fenv.h

// Rounding mode:
    enum
    {
        FE_TONEAREST = 0,
        FE_DOWNWARD = 1,
        FE_UPWARD = 2,
        FE_TOWARDZERO = 3
    };

// FP exceptions:
    enum
    {
        FE_INVALID = 1,
        FE_DENORMAL = 2,
        FE_DIVBYZERO = 4,
        FE_OVERFLOW = 8,
        FE_UNDERFLOW = 16,
        FE_INEXACT = 32,
    };

// C99 FP Exception functions
void 	feclearexcept (int excepts) ;
void 	fegetexceptflag (fexcept_t *flagp, int excepts) ;
void 	feraiseexcept (int excepts) ;
void 	fesetexceptflag (const fexcept_t *flagp, int excepts) ;
int  	fetestexcept (int excepts)

// C99 FP Rounding control
int	fegetround (void) ;
int 	fesetround (int round) ;

// C99 FP Environment control
void	fegetenv (fenv_t *envp) ;
int 	feholdexcept (fenv_t *envp) ;
void 	fesetenv (const fenv_t *envp) ;
void 	feupdateenv (const fenv_t *envp) ;


70.2.1.2. ВЕКТОРНЫЕ ТИПЫ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

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

Основная проблема, в том что не все компиляторы дают человеческие типы данных которые
позволяют с этим работать. Например Microsoft Visual C++ не дает - тем не менее есть
базовые типы и intrinsic операции (встоеные в компилятор и маппирующие вызовы псевдофункций
на конкретную генерацию команд процессора).

Поэтому для работы с такими типами данных приходиться писать С++ обвязки:

  Microsoft/Intel instrisics

// mmintrin.h

typedef union __declspec(intrin_type) _CRT_ALIGN(8) __m64
{
    unsigned __int64    m64_u64;
    float               m64_f32[2];
    __int8              m64_i8[8];
    __int16             m64_i16[4];
    __int32             m64_i32[2];
    __int64             m64_i64;
    unsigned __int8     m64_u8[8];
    unsigned __int16    m64_u16[4];
    unsigned __int32    m64_u32[2];
} __m64;

/* General support intrinsics */
void  _m_empty(void);
__m64 _m_from_int(int _I);
int   _m_to_int(__m64 _M);
__m64 _m_packsswb(__m64 _MM1, __m64 _MM2);
__m64 _m_packssdw(__m64 _MM1, __m64 _MM2);
__m64 _m_packuswb(__m64 _MM1, __m64 _MM2);
__m64 _m_punpckhbw(__m64 _MM1, __m64 _MM2);
__m64 _m_punpckhwd(__m64 _MM1, __m64 _MM2);
__m64 _m_punpckhdq(__m64 _MM1, __m64 _MM2);
__m64 _m_punpcklbw(__m64 _MM1, __m64 _MM2);
__m64 _m_punpcklwd(__m64 _MM1, __m64 _MM2);
__m64 _m_punpckldq(__m64 _MM1, __m64 _MM2);

/* Packed arithmetic intrinsics */
__m64 _m_paddb(__m64 _MM1, __m64 _MM2);
__m64 _m_paddw(__m64 _MM1, __m64 _MM2);
__m64 _m_paddd(__m64 _MM1, __m64 _MM2);
__m64 _m_paddsb(__m64 _MM1, __m64 _MM2);
__m64 _m_paddsw(__m64 _MM1, __m64 _MM2);
__m64 _m_paddusb(__m64 _MM1, __m64 _MM2);
__m64 _m_paddusw(__m64 _MM1, __m64 _MM2);
__m64 _m_psubb(__m64 _MM1, __m64 _MM2);
__m64 _m_psubw(__m64 _MM1, __m64 _MM2);
__m64 _m_psubd(__m64 _MM1, __m64 _MM2);
__m64 _m_psubsb(__m64 _MM1, __m64 _MM2);
__m64 _m_psubsw(__m64 _MM1, __m64 _MM2);
__m64 _m_psubusb(__m64 _MM1, __m64 _MM2);
__m64 _m_psubusw(__m64 _MM1, __m64 _MM2);
__m64 _m_pmaddwd(__m64 _MM1, __m64 _MM2);
__m64 _m_pmulhw(__m64 _MM1, __m64 _MM2);
__m64 _m_pmullw(__m64 _MM1, __m64 _MM2);

/* Shift intrinsics */
__m64 _m_psllw(__m64 _M, __m64 _Count);
__m64 _m_psllwi(__m64 _M, int _Count);
__m64 _m_pslld(__m64 _M, __m64 _Count);
__m64 _m_pslldi(__m64 _M, int _Count);
__m64 _m_psllq(__m64 _M, __m64 _Count);
__m64 _m_psllqi(__m64 _M, int _Count);
__m64 _m_psraw(__m64 _M, __m64 _Count);
__m64 _m_psrawi(__m64 _M, int _Count);
__m64 _m_psrad(__m64 _M, __m64 _Count);
__m64 _m_psradi(__m64 _M, int _Count);
__m64 _m_psrlw(__m64 _M, __m64 _Count);
__m64 _m_psrlwi(__m64 _M, int _Count);
__m64 _m_psrld(__m64 _M, __m64 _Count);
__m64 _m_psrldi(__m64 _M, int _Count);
__m64 _m_psrlq(__m64 _M, __m64 _Count);
__m64 _m_psrlqi(__m64 _M, int _Count);

/* Logical intrinsics */
__m64 _m_pand(__m64 _MM1, __m64 _MM2);
__m64 _m_pandn(__m64 _MM1, __m64 _MM2);
__m64 _m_por(__m64 _MM1, __m64 _MM2);
__m64 _m_pxor(__m64 _MM1, __m64 _MM2);

/* Comparison intrinsics */
__m64 _m_pcmpeqb(__m64 _MM1, __m64 _MM2);
__m64 _m_pcmpeqw(__m64 _MM1, __m64 _MM2);
__m64 _m_pcmpeqd(__m64 _MM1, __m64 _MM2);
__m64 _m_pcmpgtb(__m64 _MM1, __m64 _MM2);
__m64 _m_pcmpgtw(__m64 _MM1, __m64 _MM2);
__m64 _m_pcmpgtd(__m64 _MM1, __m64 _MM2);

/* Utility intrinsics */
__m64 _mm_setzero_si64(void);
__m64 _mm_set_pi32(int _I1, int _I0);
__m64 _mm_set_pi16(short _S3, short _S2, short _S1, short _S0);
__m64 _mm_set_pi8(char _B7, char _B6, char _B5, char _B4,
                  char _B3, char _B2, char _B1, char _B0);
__m64 _mm_set1_pi32(int _I);
__m64 _mm_set1_pi16(short _S);
__m64 _mm_set1_pi8(char _B);
__m64 _mm_setr_pi32(int _I1, int _I0);
__m64 _mm_setr_pi16(short _S3, short _S2, short _S1, short _S0);
__m64 _mm_setr_pi8(char _B7, char _B6, char _B5, char _B4,
                   char _B3, char _B2, char _B1, char _B0);

//   xmmintrin.h

typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128 {
     float               m128_f32[4];
     unsigned __int64    m128_u64[2];
     __int8              m128_i8[16];
     __int16             m128_i16[8];
     __int32             m128_i32[4];
     __int64             m128_i64[2];
     unsigned __int8     m128_u8[16];
     unsigned __int16    m128_u16[8];
     unsigned __int32    m128_u32[4];
 } __m128;

/*
 * FP, arithmetic
 */

extern __m128 _mm_add_ss(__m128 _A, __m128 _B);
extern __m128 _mm_add_ps(__m128 _A, __m128 _B);
extern __m128 _mm_sub_ss(__m128 _A, __m128 _B);
extern __m128 _mm_sub_ps(__m128 _A, __m128 _B);
extern __m128 _mm_mul_ss(__m128 _A, __m128 _B);
extern __m128 _mm_mul_ps(__m128 _A, __m128 _B);
extern __m128 _mm_div_ss(__m128 _A, __m128 _B);
extern __m128 _mm_div_ps(__m128 _A, __m128 _B);
extern __m128 _mm_sqrt_ss(__m128 _A);
extern __m128 _mm_sqrt_ps(__m128 _A);
extern __m128 _mm_rcp_ss(__m128 _A);
extern __m128 _mm_rcp_ps(__m128 _A);
extern __m128 _mm_rsqrt_ss(__m128 _A);
extern __m128 _mm_rsqrt_ps(__m128 _A);
extern __m128 _mm_min_ss(__m128 _A, __m128 _B);
extern __m128 _mm_min_ps(__m128 _A, __m128 _B);
extern __m128 _mm_max_ss(__m128 _A, __m128 _B);
extern __m128 _mm_max_ps(__m128 _A, __m128 _B);

/*
 * FP, logical
 */

extern __m128 _mm_and_ps(__m128 _A, __m128 _B);
extern __m128 _mm_andnot_ps(__m128 _A, __m128 _B);
extern __m128 _mm_or_ps(__m128 _A, __m128 _B);
extern __m128 _mm_xor_ps(__m128 _A, __m128 _B);

/*
 * FP, comparison
 */

extern __m128 _mm_cmpeq_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpeq_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmplt_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmplt_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmple_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmple_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpgt_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpgt_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpge_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpge_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpneq_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpneq_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpnlt_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpnlt_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpnle_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpnle_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpngt_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpngt_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpnge_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpnge_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpord_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpord_ps(__m128 _A, __m128 _B);
extern __m128 _mm_cmpunord_ss(__m128 _A, __m128 _B);
extern __m128 _mm_cmpunord_ps(__m128 _A, __m128 _B);
extern int _mm_comieq_ss(__m128 _A, __m128 _B);
extern int _mm_comilt_ss(__m128 _A, __m128 _B);
extern int _mm_comile_ss(__m128 _A, __m128 _B);
extern int _mm_comigt_ss(__m128 _A, __m128 _B);
extern int _mm_comige_ss(__m128 _A, __m128 _B);
extern int _mm_comineq_ss(__m128 _A, __m128 _B);
extern int _mm_ucomieq_ss(__m128 _A, __m128 _B);
extern int _mm_ucomilt_ss(__m128 _A, __m128 _B);
extern int _mm_ucomile_ss(__m128 _A, __m128 _B);
extern int _mm_ucomigt_ss(__m128 _A, __m128 _B);
extern int _mm_ucomige_ss(__m128 _A, __m128 _B);
extern int _mm_ucomineq_ss(__m128 _A, __m128 _B);

/*
 * FP, conversions
 */

extern int _mm_cvt_ss2si(__m128 _A);
extern __m64 _mm_cvt_ps2pi(__m128 _A);
extern int _mm_cvtt_ss2si(__m128 _A);
extern __m64 _mm_cvtt_ps2pi(__m128 _A);
extern __m128 _mm_cvt_si2ss(__m128, int);
extern __m128 _mm_cvt_pi2ps(__m128, __m64);

/*
 * FP, misc
 */

extern __m128 _mm_shuffle_ps(__m128 _A, __m128 _B, unsigned int _Imm8);
extern __m128 _mm_unpackhi_ps(__m128 _A, __m128 _B);
extern __m128 _mm_unpacklo_ps(__m128 _A, __m128 _B);
extern __m128 _mm_loadh_pi(__m128, __m64 const*);
extern __m128 _mm_movehl_ps(__m128, __m128);
extern __m128 _mm_movelh_ps(__m128, __m128);
extern void _mm_storeh_pi(__m64 *, __m128);
extern __m128 _mm_loadl_pi(__m128, __m64 const*);
extern void _mm_storel_pi(__m64 *, __m128);
extern int _mm_movemask_ps(__m128 _A);

/*
 * Integer extensions
 */
extern int _m_pextrw(__m64, int);
extern __m64 _m_pinsrw(__m64, int, int);
extern __m64 _m_pmaxsw(__m64, __m64);
extern __m64 _m_pmaxub(__m64, __m64);
extern __m64 _m_pminsw(__m64, __m64);
extern __m64 _m_pminub(__m64, __m64);
extern int _m_pmovmskb(__m64);
extern __m64 _m_pmulhuw(__m64, __m64);
extern __m64 _m_pshufw(__m64, int);
extern void _m_maskmovq(__m64, __m64, char *);
extern __m64 _m_pavgb(__m64, __m64);
extern __m64 _m_pavgw(__m64, __m64);
extern __m64 _m_psadbw(__m64, __m64);

/*
 * memory & initialization
 */

extern __m128 _mm_set_ss(float _A);
extern __m128 _mm_set_ps1(float _A);
extern __m128 _mm_set_ps(float _A, float _B, float _C, float _D);
extern __m128 _mm_setr_ps(float _A, float _B, float _C, float _D);
extern __m128 _mm_setzero_ps(void);
extern __m128 _mm_load_ss(float const*_A);
extern __m128 _mm_load_ps1(float const*_A);
extern __m128 _mm_load_ps(float const*_A);
extern __m128 _mm_loadr_ps(float const*_A);
extern __m128 _mm_loadu_ps(float const*_A);
extern void _mm_store_ss(float *_V, __m128 _A);
extern void _mm_store_ps1(float *_V, __m128 _A);
extern void _mm_store_ps(float *_V, __m128 _A);
extern void _mm_storer_ps(float *_V, __m128 _A);
extern void _mm_storeu_ps(float *_V, __m128 _A);
extern void _mm_prefetch(char const*_A, int _Sel);
extern void _mm_stream_pi(__m64 *, __m64);
extern void _mm_stream_ps(float *, __m128);
extern __m128 _mm_move_ss(__m128 _A, __m128 _B);

extern void _mm_sfence(void);
extern unsigned int _mm_getcsr(void);
extern void _mm_setcsr(unsigned int);

//  emmintrin.h

typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128i {
    __int8              m128i_i8[16];
    __int16             m128i_i16[8];
    __int32             m128i_i32[4];
    __int64             m128i_i64[2];
    unsigned __int8     m128i_u8[16];
    unsigned __int16    m128i_u16[8];
    unsigned __int32    m128i_u32[4];
    unsigned __int64    m128i_u64[2];
} __m128i;

typedef struct __declspec(intrin_type) _CRT_ALIGN(16) __m128d {
    double              m128d_f64[2];
} __m128d;

/*
 * DP, arithmetic
 */

extern __m128d _mm_add_sd(__m128d _A, __m128d _B);
extern __m128d _mm_add_pd(__m128d _A, __m128d _B);
extern __m128d _mm_sub_sd(__m128d _A, __m128d _B);
extern __m128d _mm_sub_pd(__m128d _A, __m128d _B);
extern __m128d _mm_mul_sd(__m128d _A, __m128d _B);
extern __m128d _mm_mul_pd(__m128d _A, __m128d _B);
extern __m128d _mm_sqrt_sd(__m128d _A, __m128d _B);
extern __m128d _mm_sqrt_pd(__m128d _A);
extern __m128d _mm_div_sd(__m128d _A, __m128d _B);
extern __m128d _mm_div_pd(__m128d _A, __m128d _B);
extern __m128d _mm_min_sd(__m128d _A, __m128d _B);
extern __m128d _mm_min_pd(__m128d _A, __m128d _B);
extern __m128d _mm_max_sd(__m128d _A, __m128d _B);
extern __m128d _mm_max_pd(__m128d _A, __m128d _B);

/*
 * DP, logicals
 */

extern __m128d _mm_and_pd(__m128d _A, __m128d _B);
extern __m128d _mm_andnot_pd(__m128d _A, __m128d _B);
extern __m128d _mm_or_pd(__m128d _A, __m128d _B);
extern __m128d _mm_xor_pd(__m128d _A, __m128d _B);

/*
 * DP, comparisons
 */

extern __m128d _mm_cmpeq_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpeq_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmplt_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmplt_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmple_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmple_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpgt_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpgt_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpge_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpge_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpneq_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpneq_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpnlt_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpnlt_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpnle_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpnle_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpngt_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpngt_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpnge_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpnge_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpord_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpord_sd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpunord_pd(__m128d _A, __m128d _B);
extern __m128d _mm_cmpunord_sd(__m128d _A, __m128d _B);
extern int _mm_comieq_sd(__m128d _A, __m128d _B);
extern int _mm_comilt_sd(__m128d _A, __m128d _B);
extern int _mm_comile_sd(__m128d _A, __m128d _B);
extern int _mm_comigt_sd(__m128d _A, __m128d _B);
extern int _mm_comige_sd(__m128d _A, __m128d _B);
extern int _mm_comineq_sd(__m128d _A, __m128d _B);
extern int _mm_ucomieq_sd(__m128d _A, __m128d _B);
extern int _mm_ucomilt_sd(__m128d _A, __m128d _B);
extern int _mm_ucomile_sd(__m128d _A, __m128d _B);
extern int _mm_ucomigt_sd(__m128d _A, __m128d _B);
extern int _mm_ucomige_sd(__m128d _A, __m128d _B);
extern int _mm_ucomineq_sd(__m128d _A, __m128d _B);

/*
 * DP, converts
 */

extern __m128d _mm_cvtepi32_pd(__m128i _A);
extern __m128i _mm_cvtpd_epi32(__m128d _A);
extern __m128i _mm_cvttpd_epi32(__m128d _A);
extern __m128 _mm_cvtepi32_ps(__m128i _A);
extern __m128i _mm_cvtps_epi32(__m128 _A);
extern __m128i _mm_cvttps_epi32(__m128 _A);
extern __m128 _mm_cvtpd_ps(__m128d _A);
extern __m128d _mm_cvtps_pd(__m128 _A);
extern __m128 _mm_cvtsd_ss(__m128 _A, __m128d _B);
extern __m128d _mm_cvtss_sd(__m128d _A, __m128 _B);

extern int _mm_cvtsd_si32(__m128d _A);
extern int _mm_cvttsd_si32(__m128d _A);
extern __m128d _mm_cvtsi32_sd(__m128d _A, int _B);

extern __m64 _mm_cvtpd_pi32(__m128d _A);
extern __m64 _mm_cvttpd_pi32(__m128d _A);
extern __m128d _mm_cvtpi32_pd(__m64 _A);

/*
 * DP, misc
 */

extern __m128d _mm_unpackhi_pd(__m128d _A, __m128d _B);
extern __m128d _mm_unpacklo_pd(__m128d _A, __m128d _B);
extern int _mm_movemask_pd(__m128d _A);
extern __m128d _mm_shuffle_pd(__m128d _A, __m128d _B, int _I);

/*
 * DP, loads
 */

extern __m128d _mm_load_pd(double const*_Dp);
extern __m128d _mm_load1_pd(double const*_Dp);
extern __m128d _mm_loadr_pd(double const*_Dp);
extern __m128d _mm_loadu_pd(double const*_Dp);
extern __m128d _mm_load_sd(double const*_Dp);
extern __m128d _mm_loadh_pd(__m128d _A, double const*_Dp);
extern __m128d _mm_loadl_pd(__m128d _A, double const*_Dp);

/*
 * DP, sets
 */

extern __m128d _mm_set_sd(double _W);
extern __m128d _mm_set1_pd(double _A);
extern __m128d _mm_set_pd(double _Z, double _Y);
extern __m128d _mm_setr_pd(double _Y, double _Z);
extern __m128d _mm_setzero_pd(void);
extern __m128d _mm_move_sd(__m128d _A, __m128d _B);

/*
 * DP, stores
 */

extern void _mm_store_sd(double *_Dp, __m128d _A);
extern void _mm_store1_pd(double *_Dp, __m128d _A);
extern void _mm_store_pd(double *_Dp, __m128d _A);
extern void _mm_storeu_pd(double *_Dp, __m128d _A);
extern void _mm_storer_pd(double *_Dp, __m128d _A);
extern void _mm_storeh_pd(double *_Dp, __m128d _A);
extern void _mm_storel_pd(double *_Dp, __m128d _A);

/*
 * Integer, arithmetic
 */

extern __m128i _mm_add_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_add_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_add_epi32(__m128i _A, __m128i _B);
extern __m64 _mm_add_si64(__m64 _A, __m64 _B);
extern __m128i _mm_add_epi64(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epu8(__m128i _A, __m128i _B);
extern __m128i _mm_adds_epu16(__m128i _A, __m128i _B);
extern __m128i _mm_avg_epu8(__m128i _A, __m128i _B);
extern __m128i _mm_avg_epu16(__m128i _A, __m128i _B);
extern __m128i _mm_madd_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_max_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_max_epu8(__m128i _A, __m128i _B);
extern __m128i _mm_min_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_min_epu8(__m128i _A, __m128i _B);
extern __m128i _mm_mulhi_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_mulhi_epu16(__m128i _A, __m128i _B);
extern __m128i _mm_mullo_epi16(__m128i _A, __m128i _B);
extern __m64 _mm_mul_su32(__m64 _A, __m64 _B);
extern __m128i _mm_mul_epu32(__m128i _A, __m128i _B);
extern __m128i _mm_sad_epu8(__m128i _A, __m128i _B);
extern __m128i _mm_sub_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_sub_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_sub_epi32(__m128i _A, __m128i _B);
extern __m64 _mm_sub_si64(__m64 _A, __m64 _B);
extern __m128i _mm_sub_epi64(__m128i _A, __m128i _B);
extern __m128i _mm_subs_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_subs_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_subs_epu8(__m128i _A, __m128i _B);
extern __m128i _mm_subs_epu16(__m128i _A, __m128i _B);

/*
 * Integer, logicals
 */

extern __m128i _mm_and_si128(__m128i _A, __m128i _B);
extern __m128i _mm_andnot_si128(__m128i _A, __m128i _B);
extern __m128i _mm_or_si128(__m128i _A, __m128i _B);
extern __m128i _mm_xor_si128(__m128i _A, __m128i _B);

/*
 * Integer, shifts
 */

extern __m128i _mm_slli_si128(__m128i _A, int _Imm);
extern __m128i _mm_slli_epi16(__m128i _A, int _Count);
extern __m128i _mm_sll_epi16(__m128i _A, __m128i _Count);
extern __m128i _mm_slli_epi32(__m128i _A, int _Count);
extern __m128i _mm_sll_epi32(__m128i _A, __m128i _Count);
extern __m128i _mm_slli_epi64(__m128i _A, int _Count);
extern __m128i _mm_sll_epi64(__m128i _A, __m128i _Count);
extern __m128i _mm_srai_epi16(__m128i _A, int _Count);
extern __m128i _mm_sra_epi16(__m128i _A, __m128i _Count);
extern __m128i _mm_srai_epi32(__m128i _A, int _Count);
extern __m128i _mm_sra_epi32(__m128i _A, __m128i _Count);
extern __m128i _mm_srli_si128(__m128i _A, int _Imm);
extern __m128i _mm_srli_epi16(__m128i _A, int _Count);
extern __m128i _mm_srl_epi16(__m128i _A, __m128i _Count);
extern __m128i _mm_srli_epi32(__m128i _A, int _Count);
extern __m128i _mm_srl_epi32(__m128i _A, __m128i _Count);
extern __m128i _mm_srli_epi64(__m128i _A, int _Count);
extern __m128i _mm_srl_epi64(__m128i _A, __m128i _Count);

/*
 * Integer, comparisons
 */

extern __m128i _mm_cmpeq_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_cmpeq_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_cmpeq_epi32(__m128i _A, __m128i _B);
extern __m128i _mm_cmpgt_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_cmpgt_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_cmpgt_epi32(__m128i _A, __m128i _B);
extern __m128i _mm_cmplt_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_cmplt_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_cmplt_epi32(__m128i _A, __m128i _B);

/*
 * Integer, converts
 */

extern __m128i _mm_cvtsi32_si128(int _A);
extern int _mm_cvtsi128_si32(__m128i _A);

/*
 * Integer, misc
 */

extern __m128i _mm_packs_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_packs_epi32(__m128i _A, __m128i _B);
extern __m128i _mm_packus_epi16(__m128i _A, __m128i _B);
extern int _mm_extract_epi16(__m128i _A, int _Imm);
extern __m128i _mm_insert_epi16(__m128i _A, int _B, int _Imm);
extern int _mm_movemask_epi8(__m128i _A);
extern __m128i _mm_shuffle_epi32(__m128i _A, int _Imm);
extern __m128i _mm_shufflehi_epi16(__m128i _A, int _Imm);
extern __m128i _mm_shufflelo_epi16(__m128i _A, int _Imm);
extern __m128i _mm_unpackhi_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_unpackhi_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_unpackhi_epi32(__m128i _A, __m128i _B);
extern __m128i _mm_unpackhi_epi64(__m128i _A, __m128i _B);
extern __m128i _mm_unpacklo_epi8(__m128i _A, __m128i _B);
extern __m128i _mm_unpacklo_epi16(__m128i _A, __m128i _B);
extern __m128i _mm_unpacklo_epi32(__m128i _A, __m128i _B);
extern __m128i _mm_unpacklo_epi64(__m128i _A, __m128i _B);

/*
 * Integer, loads
 */

extern __m128i _mm_load_si128(__m128i const*_P);
extern __m128i _mm_loadu_si128(__m128i const*_P);
extern __m128i _mm_loadl_epi64(__m128i const*_P);

/*
 * Integer, sets
 */

extern __m128i _mm_set_epi64(__m64 _Q1, __m64 _Q0);
extern __m128i _mm_set_epi32(int _I3, int _I2, int _I1, int _I0);
extern __m128i _mm_set_epi16(short _W7, short _W6, short _W5, short _W4,
                             short _W3, short _W2, short _W1, short _W0);
extern __m128i _mm_set_epi8(char _B15, char _B14, char _B13, char _B12,
                            char _B11, char _B10, char _B9, char _B8,
                            char _B7, char _B6, char _B5, char _B4,
                            char _B3, char _B2, char _B1, char _B0);
extern __m128i _mm_set1_epi64(__m64 _Q);
extern __m128i _mm_set1_epi32(int _I);
extern __m128i _mm_set1_epi16(short _W);
extern __m128i _mm_set1_epi8(char _B);
extern __m128i _mm_setl_epi64(__m128i _Q);
extern __m128i _mm_setr_epi64(__m64 _Q0, __m64 _Q1);
extern __m128i _mm_setr_epi32(int _I0, int _I1, int _I2, int _I3);
extern __m128i _mm_setr_epi16(short _W0, short _W1, short _W2, short _W3,
                              short _W4, short _W5, short _W6, short _W7);
extern __m128i _mm_setr_epi8(char _B15, char _B14, char _B13, char _B12,
                             char _B11, char _B10, char _B9, char _B8,
                             char _B7, char _B6, char _B5, char _B4,
                             char _B3, char _B2, char _B1, char _B0);
extern __m128i _mm_setzero_si128(void);

/*
 * Integer, stores
 */

extern void _mm_store_si128(__m128i *_P, __m128i _B);
extern void _mm_storeu_si128(__m128i *_P, __m128i _B);
extern void _mm_storel_epi64(__m128i *_P, __m128i _Q);
extern void _mm_maskmoveu_si128(__m128i _D, __m128i _N, char *_P);

/*
 * Integer, moves
 */

extern __m128i _mm_move_epi64(__m128i _Q);
extern __m128i _mm_movpi64_epi64(__m64 _Q);
extern __m64 _mm_movepi64_pi64(__m128i _Q);

/*
 * Cacheability support
 */

extern void _mm_stream_pd(double *_Dp, __m128d _A);
extern void _mm_stream_si128(__m128i *_P, __m128i _A);
extern void _mm_clflush(void const*_P);
extern void _mm_lfence(void);
extern void _mm_mfence(void);
extern void _mm_stream_si32(int *_P, int _I);
extern void _mm_pause(void);


70.2.1.3. ПОЛЬЗОВАТЕЛЬСКИЕ ТИПЫ ДЛЯ ЧИСЛОВЫХ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

Типовые пользовательские (невстроенные) типы для числовых данных
    Комплексные числа
        иногда бывают и встроенными
    BigNums
    Рациональные числа (x/y)
    Целые типы с арифметикой с насыщением
    Целые типы с модульной арифметикой
    Целые типы с полиномальной арифметикой
    Матрицы

  Рекомендации по имплементации числовых типов

THIS SECTION IS UNDER CONSTRUCTION

Операции вида OP=, например +=, -= возвращаем результат по ссылке
остальные операции например +, - возвращаем по значению

Достаточно одного сравнения >  (больше), все остальные можно из него вывести.

  Комплексные числа

// C++ <complex>
// T is: float, double, long double

template<typename T> class complex
{
public:
      typedef T value_type;

      complex(const T& re = T(  ), const T& im = T(  ));
        complex(const complex& z);
        template<typename X> complex(const complex<X>& z);

      T real(  ) const;
        T imag(  ) const;

      complex& operator= (const T& x);
      complex& operator+=(const T& x);
      complex& operator-=(const T& x);
      complex& operator*=(const T& x);
      complex& operator/=(const T& x);
      complex& operator=(const complex& z);
      template<typename X> complex& operator= (const complex<X>& z);
      template<typename X> complex& operator+=(const complex<X>& z);
      template<typename X> complex& operator-=(const complex<X>& z);
      template<typename X> complex& operator*=(const complex<X>& z);
      template<typename X> complex& operator/=(const complex<X>& z);
};

template<typename T> T abs(const complex<T>& z);
template<typename T> T arg(const complex<T>& z);
template<typename T> complex<T> conj(const complex<T>& z);
template<typename T> complex<T> cos(const complex<T>& z);
template<typename T> complex<T> cosh(const complex<T>& z);
template<typename T> complex<T> exp(const complex<T>& z);
template<typename T> T imag(const complex<T>& z);
template<typename T> complex<T> log(const complex<T>& z);
template<typename T> complex<T> log10(const complex<T>& z);
template<typename T> T norm(const complex<T>& z);
template<typename T> complex<T> polar(const T& r, const T& theta);
template<class T>  complex<T> pow(const complex<T>& x, int y);
template<class T>  complex<T> pow(const complex<T>& x, const T& y);
template<class T>  complex<T> pow(const complex<T>& x, const complex<T>& y);
template<class T>  complex<T> pow(const T& x, const complex<T>& y);
template<typename T> T real(const complex<T>& z);
template<typename T> complex<T> sin(const complex<T>& z);
template<typename T> complex<T> sinh(const complex<T>& z);
template<typename T> complex<T> sqrt(const complex<T>& z);
template<typename T> complex<T> tan(const complex<T>& z);
template<typename T> complex<T> tanh(const complex<T>& z);

template<typename T>  complex<T> operator+(const complex<T>& z);
template<typename T>  complex<T>  operator+(const complex<T>& x, const complex<T>& y);
template<typename T>  complex<T>  operator+(const complex<T>& x, const T& y);
template<typename T>  complex<T>  operator+(const T& x, const complex<T>& y);
template<typename T>  complex<T> operator-(const complex<T>&);
template<typename T>  complex<T> operator-(const complex<T>&, const complex<T>&);
template<typename T>  complex<T> operator-(const complex<T>&, const T&);
template<typename T>  complex<T> operator-(const T&, const complex<T>&);
template<typename T>  complex<T> operator*(const complex<T>&, const complex<T>&);
template<typename T>  complex<T> operator*(const complex<T>&, const T&);
template<typename T>  complex<T> operator*(const T&, const complex<T>&);
template<typename T>  complex<T> operator/(const complex<T>&, const complex<T>&);
template<typename T>  complex<T> operator/(const complex<T>&, const T&);
template<typename T>  complex<T> operator/(const T&, const complex<T>&);
template<typename T>  bool operator==(const complex<T>&, const complex<T>&);
template<typename T>  bool operator==(const complex<T>&, const T&);
template<typename T>  bool operator==(const T&, const complex<T>&);
template<typename T>  bool operator!=(const complex<T>&, const complex<T>&);
template<typename T>  bool operator!=(const complex<T>&, const T&);
template<typename T>  bool operator!=(const T&, const complex<T>&);

  BigNum

  Рациональные числа

  Арифметика с насыщением

  Арифметика по модулю

  Арифметика матриц

  Арифметика полиномов


70.2.2. СТРУКТУРЫ И ВЫРАВНИВАНИЕ

structs
unions

THIS SECTION IS UNDER CONSTRUCTION

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

Понятно что обращения к отдельным байтам будут выровнены
в любом случае:

Рассмотрим CPU c 16-битной шиной данных:

Обращение к 2байтовым словам:

50% выровнены   - 1 такт шины
50% невыровнены - 2 такта шины

Обращения к 4байтовым словам:

50% выровнены   - 2 такта шины
50% невыровнены - 3 такта шины

Рассмотрим CPU c 32-битной шиной данных:

Обращения к 2байтовым словам:

50% выровнены  -  1 такт шины
25% невыровнены но внутри 4байт - 1 такт шины
25% невыровнены пересекают границу 4байт - 2 такта шины

Обращения к 4х байтовым словам

25% выровнены  - 1 такт шины
75% невыровнены - 2 такта шины

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

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

Выравнивание влияет на структуры:
Пусть у нас есть структура типа:

    struct	A
    {
        char	  c;	// 1 byte integer
        long long l;	// 8 byte integer
    };

в зависимости от выравнивания мы можем иметь:
Для модели ILP32:

   BYTE   0   1   2   3
    +---+---+---+---+	Выравнивание = 1
   +00	| c |     l     |
    +---+---+---+---+       Смещение(l) = +0001
   +04  |       l       |       Размер(A)   =  9 bytes
    +---+---+---+---+
   +08	| l |
    +---+

   BYTE   0   1   2   3
    +---+---+---+---+	Выравнивание = 4
   +00	| c |XXXXXXXXXXX|
    +---+---+---+---+       Смещение(l) = +0004
   +04  |       l       |       Размер(A)   =  12 bytes
    +---+---+---+---+
   +08	|       l       |
    +---+---+---+---+

   BYTE   0   1   2   3
    +---+---+---+---+	Выравнивание = 8
   +00	| c |XXXXXXXXXXX|
    +---+---+---+---+
   +04  |XXXXXXXXXXXXXXX|
    +---+---+---+---+       Смещение(l) = +0008
   +08  |       l       |       Размер(A)   =  16 bytes
    +---+---+---+---+
   +0C	|       l       |
    +---+---+---+---+

Но самый ужас это:

   BYTE   0   1   2   3
    +---+---+---+---+	Выравнивание = 8
+00	|       l       |	Длинна равна 16 bytes,
    +---+---+---+---+	потому что внутри массива где
+04	|       l       |	данные идут подряд
    +---+---+---+---+       l все равно должно быть
+08	| c |XXXXXXXXXXX|	выровнена на 8
    +---+---+---+---+       Поэтому хоть хвост и остается
+0C	|XXXXXXXXXXXXXXX|       он не используется.
    +---+---+---+---+

Рассмотрим еще примеры:

    struct
    {
        char	c;
        short	s;
        long	l;
        long long ll;
    };

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

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

    struct
    {
        char	c1;
        short	s1;
        char	c2;
        long	l2;
        char	c3;
        long	l3;
        long long i3;
    };

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

Вырвниввние = 2

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

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

Плотная упаковка (CLR)

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

    struct
    {
        long	l;
        short	s;
    };

Плотная упаковка, align = 1, sizeof = 6

Выравнивание = 4, sizeof = 8
потому что в массиве следующий элемент l должен быть
выравнен на 8.

  Полезные макросы для структур

size_t offsetof(structname, membername)

// stddef.h
#ifdef __cplusplus
#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&reinterpret_cast((((s *)0)->m)) )
#else
#define offsetof(s,m)   (size_t)&reinterpret_cast((((s *)0)->m))
#endif
#else
#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif
#endif	/* __cplusplus */

  Справочная информация

Выравнивание статических данных:

Выравнивание данных в структурах:


70.2.2.1. БИТЫ И БИТОВЫЕ ПОЛЯ

THIS SECTION IS UNDER CONSTRUCTION

Поскольку с битовыми полями есть проблемы по endian (см секцию 70.2.1),
(различный порядок bitfields)
то часто наиболее переносимый вариант - это ручная работа.

  Работа с отдельными битами:

Проверка бита M:
    (X >> M) & 1

Установка бита M:
    X |= (1 << M)

Очистка бита  M:
    X &= ~(1 << M)

Инвертирование бита M:
    X ^= (1 << N)

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

x86:
    bt	bit test
    bts	bit test & set
    btr	bit test & reset
    btc	bit test & complement

  Работа с битовыми полями

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

Собственно есть акселерация на уровне инструкций и в CISC, и в части RISC
микропроцессоров (например Power PC).

Инструкция по работе с битовыми строками можно прочитать в секции
35.2.1.9. ОПЕРАЦИИ ПО РАБОТЕ С БИТАМИ И БИТОВЫМИ СТРОКАМИ

  Битовые маски

Создание битовой маски:

    mask = 0{a}1{b}0{c}

    mask = ((1 << b) - 1) << c

Специальные случаи:

    mask = 0{all}1{b}

    mask = (1 << b) - 1

    mask = 1{all}0{b}

    mask = - (1 << b)

Что делают маски:

  Выборка Unsingned битового поля

    mask = 0{a}1{b}0{c}

    bf = (X & mask) >> c;

  Выборка Signed битового поля и его знаковое расширение

    mask = 0{a}1{b}0{c}

    signmask = (1 << (b - 1));
    bf = (X & mask) >> c;
    bf |= - (bf & signmask);

  Вставка битового поля

    mask = 0{a}1{b}0{c}

    X = (X & ~mask) | ((bf << c) & mask)


70.2.3. ПРЕДСТАВЛЕНИЕ СИМВОЛОВ

Cуществуют различные методы представления символов.

  ASCII

Однобайтовое Представление символов
    ASCII

ASCII (American Standart Code for Information Interchange).
       Американский стандартный код для обмена информаций.
       описывает 7 бит

 --+----------------------------------------------------------------
     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F
 --+----------------------------------------------------------------
00 | NUL SOH STX ETX EOT ENQ ACK BEL BS  HT  LF  VT  FF  CR  SO  SI
10 | DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM  SUB ESC FS  GS  RS  US
20 | SPC  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
30 |  0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
40 |  @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
50 |  P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
60 |  `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
70 |  p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~  DEL
 --+----------------------------------------------------------------

ASCII control codes:

    ----------------------------------
    00 	NUL (null)
    01 	SOH (start of heading)
    02 	STX (start of text)
    03 	ETX (end of text)
    04 	EOT (end of transmission)
    05 	ENQ (enquiry)
    06 	ACK (acknowledge)
    07 	BEL (bell)
    08 	BS (backspace)
    09 	TAB (horizontal tab)
    0A 	LF (NL line feed, new line)
    0B 	VT (vertical tab)
    0C 	FF (NP form feed, new page)
    0D 	CR (carriage return)
    0E 	SO (shift out)
    0F 	SI (shift in)
    10 	DLE (data link escape)
    11 	DC1 (device control 1)
    12 	DC2 (device control 2)
    13 	DC3 (device control 3)
    14 	DC4 (device control 4)
    15 	NAK (negative acknowledge)
    16 	SYN (synchronous idle)
    17 	ETB (end of trans. block)
    18 	CAN (cancel)
    19 	EM (end of medium)
    1A 	SUB (substitute)
    1B 	ESC (escape)
    1C 	FS (file separator)
    1D 	GS (group separator)
    1E 	RS (record separator)
    1F 	US (unit separator)
    7F 	DEL (delete)
    ----------------------------------

        +----------+
            |          |		ASCII-Art
    +----------+   |
    |	   |   \
    |	   |    --------\
    |	   \             \
    |	    ----------\   \
    |------+               \ /
    |       \               \
    \        |              /
      \      |             /
        ------------------+

Я нарисовал носки, лишь используя ASCII.

  Кодовые страницы

Если латинский алфавит отображается в ASCII, то для других
алфавитов- проблемы. Т.к. есть символы которые непредставимы в ASCII.
Поэтому делают расширение ASCII до 8-бит внося дополнительные символы.

Пример кодовой страницы Windows CP1250 (Western Europe)

Т.к. много языков и стандартов, то много и codepages.

Основные кодовые страницы для русского языка:

DOS 866 Codepage		DOS, OS/2, Windows	ibm866
Windows 1251 Codepage		Windows			Windows-1251
KOI8-R				UNIX                	koi8-r
ISO8859-5			OpenVMS			iso-8859-5
Machintosh CP10007		Machintosh		x-mac-cyrillic
UNICODE				*			*

Пример текстa:
-------------------------------------------------------------------------------
Привет мир
-------------------------------------------------------------------------------

CP Windows 1251:
-------------------------------------------------------------------------------
00000000: cf f0 e8 e2 e5 f2 20 ec e8 f0                     [Привет мир      ]
-------------------------------------------------------------------------------

CP DOS 866:
-------------------------------------------------------------------------------
00000000: 8f e0 a8 a2 a5 e2 20 ac a8 e0                     [_аЁў_в ¬Ёа      ]
                                                            [Привет мир      ]
-------------------------------------------------------------------------------

KOI-8-R очень специфическая кодировка. Русские буквы в ней расположены так что
бы соответствовать англиским фонетическим аналогам.
Если убрать старший бит из байта - то KOI-8-R превратится в трудом но читаемый
транслит.
Пример:
    KOI-8-R:	"Русский Текст"
    ACSII:		"rUSSKIJ tEKST"

Windows CP1251 (Cyrilic)

DOS CP866 (Cyrilic)

ISO8859-5 (Cyrilic)

KOI-8-R (Cyrilic RUS)

Machintosh CP10007 (Machintosh Cyrilic)

MIC (Болгарская кодировка)

  Multibyte

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

Пример главной таблицы multibyte кодировки 932 (Japanise):

Пример таблицы кодировки 932 (если первый байт равен 88h):

  EBCDIC

EBCDIC (Extended Binary-Coded Decimal Interchange code)
используется в IBM's mainframes.

Такая чудовищная таблица потому что основа ввода в т врмена это перфокарты.

---------------------------------------------------------------------------------
    00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F
---------------------------------------------------------------------------------
00     NULL		PF  HT  LC  DEL
10			RES NL  BS  IL
20                      BYP LF  EOB PRE         SM
30			PN  RS  UC  EOT
40      SP                                      C$  .   <   (   +   |
50      &					!   $   *   )   ;   ^
60      _   /					    ,   %   -   >   ?
70						:   #   @   '   =   "
80          a   b   c   d   e   f   g   h   i
90	    j   k   l   m   n   o   p   q   r
A0              s   t   u   v   w   x   y   z
B0
C0          A   B   C   D   E   F   G   H   I
D0	    J   K   L   M   N   O   P   Q   R
E0		S   T   U   V   W   X   Y   Z
F0      0   1   2   3   4   5   6   7   8   9
---------------------------------------------------------------------------------

NULL
PF	Perforator off
HT	Horisontal tabulation
LC	Lowercase char
DEL	delete
RES	restore
NL	new line
BS	backspace
IL	illegal
BYP	bypass
LF	line feed
EOB	end of block
PRE	prefix
SM	set mode
PN	perforator on
RS	Read stop
UC	uppercase char
EOT	end of transfer
SP	space
C$	cent (1/100 of $)

Кстати у EBCDIC тоже есть кодовые страницы.

  Текстовые файлы

К сожалению кроме кодовых страниц есть и другие заморочки:

Рассмотрим текстовый файл:
-------------------------
Hello
world
-------------------------

CP/M и унаследованные (например MSX-DOS)
    разделитель строк - последовательность CR LF
    текстовый файл должен кончаться символом EOF  (26)
--------------------------
00000000: 48 65 6c 6c 6f 0d 0a 77 6f 72 64 1A .. .. ..      [Hello..world.   ]
--------------------------

DOS/Windows:
    разделитель строк - последовательность CR LF
--------------------------
00000000: 48 65 6c 6c 6f 0d 0a 77 6f 72 64 .. .. .. ..      [Hello..world    ]
--------------------------

UNIX:
    разделитель строк - LF
--------------------------
00000000: 48 65 6c 6c 6f 0a 77 6f 72 64 .. .. .. .. ..      [Hello.world     ]
--------------------------

Machintosh:
    разделитель строк - CR
--------------------------
00000000: 48 65 6c 6c 6f 0d 77 6f 72 64 .. .. .. .. ..      [Hello.world     ]
--------------------------

  UNICODE

Честно говоря тут тоже имеется Endian.
ASCII однозначно мапируется по принципу:

0000-1FFF	Alphabets (Latin,Cirillic..)
2000-2FFF	Symbols (Mathematical...)
3000-3FFF	Chinese,Japanese,Korean phonetic symbols
4000-DFFF	Chinese,Japanese,Korean symbols
E000-EFFF	Reserved
F000-FFFF	User defined

Более детальное описание:
----------------------------------------------------------
Базовый латинский алфавит 		(0000-007F)
Дополнительные символы Latin-1 		(0080-00FF)
Расширенный латинский алфавит-A 	(0100-017F)
Расширенный латинский алфавит-B 	(0180-024F)
Международный фонетический алфавит (IPA)(0250-02AF)
Пробельные символы 			(02B0-02FF)
диакритические символы 			(0300-036F)
Греческий и коптский алфавиты 		(0370-03FF)
Кириллица 				(0400-04FF)
Дополнительные символы кириллицы 	(0500-052F)
Армянский алфавит 			(0530-058F)
Еврейский алфавит 			(0590-05FF)
Арабский алфавит 			(0600-06FF)
Сирийский алфавит 			(0700-074F)
Доп символы арабского алфавита 		(0750-077F)
Thaana 					(0780-07BF)
Индийские письменности:
    Деванагари 			(0900-097F)
    Бенгали 			(0980-09FF)
    Gurmukhi 			(0A00-0A7F)
    Gujarati 			(0A80-0AFF)
    Oriya 				(0B00-0B7F)
    Tamil 				(0B80-0BFF)
    Telugu 				(0C00-0C7F)
    Kannada 			(0C80-0CFF)
    Malayalam 			(0D00-0D7F)
    Sinhala 			(0D80-0DFF)
Тайский алфавит 			(0E00-0E7F)
Лаосская письменность 			(0E80-0EFF)
Тибетская письменность 			(0F00-0FFF)
Бирманский алфавит 			(1000-109F)
Грузинский алфавит 			(10A0-10FF)
Отдельные буквы (Jamo) хангыль 		(1100-11FF)
Амхарский язык 				(1200-137F)
Ethiopic Supplement 			(1380-139F)
Язык чероки 				(13A0-13FF)
Unified Canadian Aboriginal Syllabics 	(1400-167F)
Ogham 					(1680-169F)
Рунный алфавит 				(16A0-16FF)
Филиппинские письменности:
    Tagalog 			(1700-171F)
    Hanunoo 			(1720-173F)
    Buhid 				(1740-175F)
    Tagbanwa 			(1760-177F)
Кхмерский алфавит 			(1780-17FF)
Монгольский алфавит 			(1800-18AF)
Limbu 					(1900-194F)
Tai Le 					(1950-197F)
New Tai Lue 				(1980-19DF)
Khmer Symbols 				(19E0-19FF)
Buginese 				(1A00-1A1F)
Фонетические расширения 		(1D00-1D7F)
Дополнительные фонетичестие расширения 	(1D80-1DBF)
Дополнительные диакритические знаки 	(1DC0-1DFF)
Latin Extended Additional 		(1E00-1EFF)
Расширенный греческий алфавит 		(1F00-1FFF)
Символы:
Пунктуация 				(2000-206F)
Надстрочные и подстрочные знаки 	(2070-209F)
Символы валют 				(20A0-20CF)
Combining Diacritical Marks for Symbols (20D0-20FF)
Letterlike Symbols 			(2100-214F)
Number Forms 				(2150-218F)
Стрелки 				(2190-21FF)
Математические операторы 		(2200-22FF)
Прочие технические символы 		(2300-23FF)
Control Pictures 			(2400-243F)
Optical Character Recognition 		(2440-245F)
Enclosed Alphanumerics 			(2460-24FF)
Символы для рисования рамок 		(2500-257F)
Block Elements 				(2580-259F)
Геометрические фигуры 			(25A0-25FF)
Прочие символы 				(2600-26FF)
Dingbats 				(2700-27BF)
Miscellaneous Mathematical Symbols-A 	(27C0-27EF)
Supplemental Arrows-A 			(27F0-27FF)
Азбука Брайля 				(2800-28FF)
Supplemental Arrows-B 			(2900-297F)
Miscellaneous Mathematical Symbols-B 	(2980-29FF)
Supplemental Mathematical Operators 	(2A00-2AFF)
Miscellaneous Symbols and Arrows 	(2B00-2BFF)
Глаголица 				(2C00-2C5F)
Коптский алфавит 			(2C80-2CFF)
Georgian Supplement 			(2D00-2D2F)
Tifinagh 				(2D30-2D7F)
Ethiopic Extended 			(2D80-2DDF)
Supplemental Punctuation 		(2E00-2E7F)
CJK Radicals Supplement 		(2E80-2EFF)
Kangxi Radicals 			(2F00-2FDF)
Ideographic Description Characters 	(2FF0-2FFF)
CJK Symbols and Punctuation 		(3000-303F)
Хирагана 				(3040-309F)
Катакана 				(30A0-30FF)
Чжуинь (Бопомофо) 			(3100-312F)
Хангыль Compatibility Jamo 		(3130-318F)
Kanbun 					(3190-319F)
Расширение Бопомофо 			(31A0-31BF)
CJK Strokes 				(31C0-31EF)
Katakana Phonetic Extensions 		(31F0-31FF)
Enclosed CJK Letters and Months 	(3200-32FF)
CJK Compatibility 			(3300-33FF)
CJK Unified Ideographs Extension A 	(3400-4DBF)
Yijing Hexagram Symbols 		(4DC0-4DFF)
CJK Unified Ideographs 			(4E00-9FFF)
Yi Syllables 				(A000-A48F)
Yi Radicals 				(A490-A4CF)
Modifier Tone Letters 			(A700-A71F)
Syloti Nagri 				(A800-A82F)
Слоги хангыль 				(AC00-D7AF)
Верхняя часть суррогатных пар 		(D800-DB7F)
Верхняя часть суррогатных пар		(DB80-DBFF)
Нижняя часть суррогатных пар 		(DC00-DFFF)
Область для частного использования 	(E000-F8FF)
CJK Compatibility Ideographs 		(F900-FAFF)
Alphabetic Presentation Forms 		(FB00-FB4F)
Arabic Presentation Forms-A 		(FB50-FDFF)
Variation Selectors 			(FE00-FE0F)
Vertical Forms 				(FE10-FE1F)
Combining Half Marks 			(FE20-FE2F)
CJK Compatibility Forms 		(FE30-FE4F)
Small Form Variants 			(FE50-FE6F)
Arabic Presentation Forms-B 		(FE70-FEFF)
Halfwidth and Fullwidth Forms 		(FF00-FFEF)
Специальные символы 			(FFF0-FFFF)
----------------------------------------------------------

Unicode (0000-007F, Latin)

Unicode (0080-00FF, Latin-1)

Unicode (0400-04FF, Cyrilic)

Все равно иероглифы все не уложили, поэтому приходится пользоватся либо кодовыми
страницами (в случае UCS-2), либо использовать UTF-16.

  Текстовые файлы в UNICODE

Рассмотрим текстовый файл:
-------------------------
Hello
world
-------------------------

UNICODE текстовый файл всегда начинается с сигнатуры feffh - которая позволяет
определить endian этого файла.

Litle-endian Unicode:
--------------------------
00000000: ff fe 48 00 65 00 6c 00 6c 00 6f 00 0d 00 0a 00   [яюH e l l o . . ]
00000010: 77 00 6f 00 72 00 64 00                           [w o r d         ]
--------------------------

Big-endian Unicode
--------------------------
00000000: fe ff 00 48 00 65 00 6c 00 6c 00 6f 00 0d 00 0a   [юя H e l l o . .]
00000010: 00 77 00 6f 00 72 00 64                           [ w o r d        ]
--------------------------

UNICODE консорциум говоритm что если в файле отсутсвует BOM (Byte Order Marker),
то по умолчанию Unicide текст должен быть big-endian.

Не стоит думать что UNICODE это только 16-бит кодировка. Стандарт использует 32-бит
символы тоже. Например есть символы для представления фишек игры домино.
Например:

Даже символы клингонского алфавита (Клингоны - одна из рас из Star Track) тоже
стандартизованы UNICODE.

Есть масса проблем связанных с программированием на C/C++ и 32-бит Unicode.
Встроенный тип wchar_t используемый для представления символов на части платформ
(например Windows) 16-битный, а на другой части (например: MacOSX) 32-битный.
И реально трудно писать переносимый код.

  UTF-8

Для лучшей совместимости был придуман UTF-8 (Unicode Transformation Format).
Основная идея - ASCII символы (00-7F) идут без изменений. Если надо записывать
уже другие символы то они записываются в виде:
    11xxxxxx	первый байт
    10xxxxxx	остальные байты

Соответственно символы записываются как:

    0000-007F	0xxxxxxx
    0080-07FF	110xxxxx  10xxxxxx
    0800-FFFF	1110xxxx  10xxxxxx  10xxxxxx

Конечно возможна неоднозначность, связанная с тем, что символ с кодом например 100h
можно записать в виде 3х байтов, но как правило стараются использовать более минимальные
упаковки.

Например символ A c кружочком (код 000C5) может быть представлен в UTF-8 как:

    C3 85
    E0 83 85

оба варианта правильные, но канонический более короткий
(мы молчим про вариант 41 СС 8A - про него поговорим позднее в секции диактрические
ужосы).

Но зато UTF-8 без изменений может представлять и 32-битные Unicode символы,
и символы с большем количеством битов. Главное, что можно четко найти границу символа
(диакрические суффиксы - это отдельная тема см ниже), и проблемы с Endian не возникает.

Системные вызовы Linux понимают UTF-8 формат имен.
А Windows работает с UTF-16LE unicode.

Соответсвенно документы начинаются с:
    UTF-8		EF BB BF
    UTF-16BE        FE FF
    UTF-16LE	FF FE
    UTF-32BE	00 00 FE FF
    UTF-32LE	FF FE 00 00

ASCII text:
-------------------------
Hello
world
-------------------------

UTF-8:
-------------------------
00000000: ef bb bf 48 65 6c 6c 6f 0d 0a 77 6f 72 6c 64      [п>їHello..world ]
-------------------------

Русский текст:
-------------------------------------------------------------------------------
Привет мир
-------------------------------------------------------------------------------

UTF-8:
-------------------------------------------------------------------------------
00000000: ef bb bf d0 9f d1 80 d0 b8 d0 b2 d0 b5 d1 82 20   [п>їР_С_РёР_РчС' ]
00000010: d0 bc d0 b8 d1 80                                 [Р_РёС_          ]
-------------------------------------------------------------------------------

  UTF-16

Серии символов
    D800-DBFF
и	DC00-DFFF

не используются для хранения символов, а используются для того что бы
представлять более старшие символы в UTF-16

Если символ умещается в 2 байта (а попасть в диапазоны D800-DBFF, DC00-DFF
он просто не может - так как символов там нету), то он просто кодируется в два байта

Если же символ выходит из двух байт но попадает в диапазон (10000-10FFFE),
то он кодируется двумя двухбайтовыми символами:

Вначале от кода символа который будет кодироваться отнимаем 10000h.
Первый в диапазоне D800-DBFF, он содержит старшие 10 бит разности в своих младших
битах.

Второй символ будет в диапазоне DC00-DFFF, его младшие 10 бит равны младшим 10 бит
символа, который мы собираемся кодировать.

Такая схема позволяет описать дo 1,114,110 символов.
Пока UTF-16 не позволяет кодировать символы с кодами более 10FFFE, не паряться, потому
что практически не надо. Но в любом случае это гораздо больше чем 65536 в простом UCS-2.

И еще раз отметим что UTF-16 имеет endian, то есть реально имеем:
    UTF16-LE
    UTF16-BE

  Ужасы языковой сортировки

Если бы дело ограничивалась только файлами, но к сожалению это проникает везде.
Когда у нас в Windows программа начинает выдавать в меню "зюки" - то у нас
системный шрифт для другой кодовой таблицы.

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

И один из ужасов это алфавитная сортировка, разные языеи используют разные методы
для сортировки.
Например для немецкого языка по стандарту DIN-2 буква

сортируется как словосочетание 'ss',

а буквы содержащие две точки сортируются как (буква)e
Например буква

сортируется по алфавиту как буквосочетание 'oe'.
А в Шведском эта же буква идет по алфавиту после буквы 'z'.

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

В инспанском например сочетание 'ch' сортируется как отдельная буква (которой нет в
алфавите).

  Unicode ужасы (Диакрические знаки)

Самое ужастное что Unicode тоже имеет неоднозначность кодирования
Например e c двумя точками может быть представлена двумя различными формами
И обе формы правильные.

Форма					UNICODE		UTF-8
Монолитной формой (precomposed)		00E9		C3 A9
Составной формой 			0065 0301	65 СС 81
(сначала e, потом диакрический знак)

Монолитная форма:

Составная форма

И получается что в составной форме буква занимает 2 (!) Unicode символа.
(Здраствуй Multibyte).

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

Для диакрических знаков выделена зона 0300-036F.

Собственно для борьбы с UNICODE ужасами служат нормализованные UNICODE кодировки,
например KD (в ней все символы приводяться из монолитной формы в составную, и в добавок
к этому раскрываются лигатуры).

  Unicode ужасы (Лигатуры)

Наиболее типичная лигатура это ff в романских языках.
Cобственно ff - это два символа f идущих подряд.

  Нормальные формы для Unicode

NFD	Каноничесая декомпозиции

NFC	Каноническая декомпозиция с последующей канонической композицией

NFKD	Совместимая декомпозиция

NFKC	Совместимая декомпозиция с последущей канонической композицией

  API для символов

// ctype.h

int	isalnum(int	c);
int	isalpha(int	c);
int	iscntrl(int	c);
int	isdigit(int	c);
int	isgraph(int	c);
int	islower(int 	c);
int	isprint(int	c);
int	ispunct(int	c);
int	isspace(int	c);
int	isupper(inc	c);
int	isxdigit(inc	c);

int	tolower(inc c);
int	toupper(inc c);

// ASCII only version:

int	isdigit(int c)
{
    return ((c >= '0') && (c <= '9')? 1: 0;
}

int     isalpha(int c)
{
    return (((c >= 'A') && (c <= 'Z')) ||
        ((c >= 'a') && (c <= 'z')))?  1 : 0;
}

int     isalnum(int c)
{
    return isdigit(c) || isalpha(c);
}

int	tolower(int c)
{
    return ((c >= 'A') && (c <= 'Z'))? c + 'a' - 'A' : c;
}

int	isascii(int c);		// входит ли в состав ASCII (0-127)
int	iscsym(int c);		// является ли символ идентивикатором (буквы/цифры + '_')

int	iswascii(wint_t c);
int	iswcsym(wint_t c);

int	isleadbyte(int c);	// является ли символ lead-байтом в multibyte символе

Имейте в виду что для UNICODE мы имеем дополнительные сущности:

Для некоторых символов возможен еще один вариант case:
    Lower case
    Upper case
    Title case

// Java

static char toLowerCase(char ch);
static char toUpperCase(char ch);
static char toTitleCase(char ch);

static boolean isTitleCase(char ch);
static boolean isLowerCase(char ch);
static boolean isUpperCase(char ch);

Кроме того есть новый класс символов: Symbol
он означает всякие там иероглифы итд

// wctype.h

int	iswalnum(wint_t	c)
int	iswalpha(wint_t c)
int	iswcntrl(wint_t c)
int	iswdigit(wint_t c)
int	iswgraph(wint_t c)
int	islower(wint_t c)
int	iswprint(wint_t c)
int	iswpunct(wint_t c)
int 	iswspace(wint_t c)
int	iswupper(wint_t c)
int	iswxdigit(wint_t c)

wint_t	towlower(wint_t c)
wint_t	towupper(wint_t c)

//C#
    System.Char.IsWhiteSpace(char c)

    IsSymbol()

//	Unicode UTF-16:
        bool	IsSurrogate(char c)
        bool	IsHighSurrogate(char c)
        bool	IsLowSurrogate(char c)
        bool	IsSurrogatePair(char highsurrogate, char lowsurrogate)

    string ConvertFromUtf32(int utf32)
    int    ConvertToUtf32(char highsurrogate, char lowsurrogate)

 Windows

int	MultiByteToWideChar(
        UINT	uCodePage,
        DWORD	dwFlags,
        PCSTR	pMultiByteStr,
        int	cbMultiByte,
        PWSTR	pWideCharStr,
        int	cchWideChar);

int	WideCharToMultiByte(
        UINT	uCodePage,
        DWORD	dwFlags,
        PCWSTR	pWideCharStr,
        int	cchWideChar,
        PSTR	pMultiByteStr,
        int	cbMultiByte,
        PCSTR	pDefaultChar,
        PBOOL	pfUsedDefaultChar);


70.2.4. УКАЗАТЕЛИ И МОДЕЛИ ПАМЯТИ

THIS SECTION IS UNDER CONSTRUCTION

Указатели используются для косвенной адрессации данных.
Указатели ОЧЕНЬ РАСПРОСТРАНЕНЫ.

    +---------+
    |Pointer O|---------->+--------------+
    +---------+	      |		     |
                  |	Data	     |
                  |		     |
                  +--------------+

Указатели можно рассматривать как целые числа.
Длинна указателя зависит от платформы.

    +---+---+---+---+
    |    Pointer    |			Windows 32-bit
    +---+---+---+---+

    +---+---+---+---+---+---+---+---+
    |	     Pointer		|       IRIX 64-bit
    +---+---+---+---+---+---+---+---+

Свойства указателей:

    Размер
    Тип
        near/far	для сегментных моделей
        data/code	для моделей памяти
    Based/Non-based

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

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

  Указатели и сегментация

На деле проблемы начинаются в первую очередь в архитектурах использующих
сегментацию.
В частности для x86 - это DOS и как апофеоз OS/2.

        Pointer
           /       \
         Near      Far

Near - внутрисегментный указатель (содержит только смещение в сегменте)
Far  - межсегментный указатель (содержит индекс сегмента и смещение в нем).

    +---+---+
    |Offset |			NEAR 16-bit pointer
    +---+---+

    +---+---+---+---+
    |Segment|Offset |       	FAR  16-bit pointer
    +---+---+---+---+

    +---+---+---+---+
    |     Offset    |		NEAR 32-bit pointer
    +---+---+---+---+

    +---+---+---+---+---+---+
    |Segment|     Offset    |       FAR  32-bit pointer
    +---+---+---+---+---+---+

Вычисление линейного адресса в реальном режиме (DOS)

Ниже адрессная арифметика для реального режима

Вычисление линейного адресса в защищенном режиме.

Huge pointers.

Адресная арифметика с huge pointers в реальном режиме

Адрессная арифметика с huge pointers в защищенном режиме

  Модели памяти

Причины существования моделей памяти:

В микропроцессорах есть команды которые позволяют более быстро работать с относительно
малыми объемами кода данных

Например - есть команда условного вызова подпрограммы, но она доступна только для
определенных размеров смещений:

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

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

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

Длинна указателя на код и данные может отличаться в разных моделях
Поэтому надо очень акуратно работать с указателями.

  Базовые указатели

Обычный указатель:

Базовый указатель:

// Visual C++

int*  vpi;                	// обычный указатель
int   __based(vpi) *  bpi;      // based указатель

// реально  *bpi  означает  *(bpi + vpi)

  Не указатели

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

  Операции над указателями

Операции которые возможны над указателями (адрессная арифметика)

    pointer + number
    pointer - number
            Возможна разная семантика
            Например прибавление sizeof от объекта на который ссылается указатель
    pointer - pointer
            Вычисляем разность между указателями

ptrdiff_t	- тип который описывает разность между указателями
          (очевидно что его размер как минимум должен быть равен размеру
           указателя)

  Smart Pointers

Smart Pointers - один из вариантов данных которые ведут себя как указатели, но обладают
             дополнительной семантикой.

  auto_ptr<> (хранение указателя в единственной копии)

    auto_ptr<> - указатель храниться только в одной копии
             если происходит присваивание то он не теряется
             (destructive copy)

Читайте секцию:
81.2.3.2.1. БОРЬБА С УТЕЧКАМИ ПАМЯТИ
Там описан auto_ptr<>

  smart_ptr<> (отслеживание ссылок на объект)

    smart pointers
        отслеживание счетчика ссылок на объект
        link list

Читайте секцию:
81.2.3.2.1. БОРЬБА С УТЕЧКАМИ ПАМЯТИ
Там описан smart pointer с отслеживанием ссылок на объект

  COW (Copy on Write)

    Клонирование объекта
        обычное
        Copy-on-Write

  Resource Locking (блокирование ресурса при обращении)

    Resource Locking
        обычный
        реентерабельный в пределах одной нити

template <class T> class lock_ptr
{
public:
    class lock_proxy
    {
        friend class lock_ptr<T>;

        lock_ptr<T>& base;

        lock_proxy(lock_ptr<T>& pbase) : base(pbase)
        {
            ::Lock(base.lock);	// Lock synchronization object
        }

        ~lock_proxy()
        {
            ::Unlock(base.lock);	// Unlock synchronization object
        }
    public:
        T* operator->()
        {
            return	base.ptr;
        }
    };

    lock_ptr(T* p) : ptr(p)
    {
        ::InitLock(lock);
    }

    ~lock_ptr()
    {
        ::DestroyLock(lock);
    }

    lock_proxy operator->()
    {
        lock_proxy proxy(const_cast<lock_ptr<T>&>(*this));
        return	proxy;
    }

    const lock_proxy operator->() const
    {
        lock_proxy proxy(const_cast<lock_ptr<T>&> (*this));
        return	proxy;
    }

private:
    T*	ptr;
    lock_t  lock;		// synchronization object
};

  Offline pointers

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

template <class T> class offline_ptr
{
public:
    offline_ptr(FILE* hFile, off_t  offset) :
        inmem(false), h(hFile), off(offset) { }

    ~offline_ptr()
    {
        if (inmem) delete ptr;
    }

    T* operator->()
    {
        if (inmem) return ptr;
        preload();
        return	ptr;
    }

    const T* operator->() const
    {
        if (inmem) return ptr;
        preload();
        return	ptr;
    }

    void  preload()
    {
        ptr = new char[sizeof(T)];	// считаем что nothrow
        if (ptr == 0) return;
        fseek(h, off, SEEK_SET);
        fread(ptr, sizeof(T), 1, h);
    }

    void  flushinv()
    {
        if (inmem)
        {
            fseek(h, off, SEEK_SET);
            fwrite(ptr, sizeof(T), 1, h);
            delete ptr;
            ptr = 0;
        }
    }

private:
    FILE*  h;	// Handle of external file object
    off_t  off;     // Offset in file
    bool   inmem;	// Is in memory
    T*     ptr;	// Pointer in memory
};

TODO:
    Прочие вопросы, например
        Проблемы с циклическими ссылками


70.2.5. MACCИВЫ

  Масссив

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

    +----------+
    |   A[0]   |
    +----------+
    |   A[1]   |
    +----------+
    =  ......  =
    +----------+
    |  A[N-1]  |
    +----------+
    |   A[N]   |
    +----------+

  Развертка массивов

Массивы могут иметь больше одного измерения.

В этом случае возникает вопрос развертки массивов (то есть как кладутся многомерные
данные в память).

2D массив: столбцы главнее

2D массив: строки главнее

итд по измерениям.

С/C++: кладем по строкам
       (сначала 0й столбец 0й строки,
        потом   1й столбец 0й строки,
       итд)

FORTRAN: кладем по столбцам
    (сначала 0й столбец 0й строки,
         потом   0й столбец 1й строки,
    итд.

char days[][10] =
{
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
};

char* days[] =
{
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
};

  Срезы массивов

  Операции с массивами

    Выборка элемента
    Запись  элемента

    Выборка среза

    Итерационный обход массива
    Поиск элемента в массиве по признаку
        Поиск элемента в неотсортированном массиве  O(N)
        Поиск элемента в отсортированном массиве    O(logN)

    Сортировка массива
        с callback по элементам
            predicate

    Добавление элемента
        одиночного/группы элементов
            в конец			O(1)
            в указанное место	O(N)

    Удаление элемента
        одиночного/группы элементов
            из конца		O(1)
            из указанного места	O(N)

    Обмен элементами в указанных позициях  O(1)

    Обращение массива  O(N)
        реверсирование порядка следования элементов массива

  Проблематика вставки/удаления элементов

Массивы позволяют прямой доступ
Но есть проблемы с вставками и удалениями элементов:

  Дополнительные примитивы работы с памятью

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

Основные примитивы работы с памятью описаны в секции
81.2.2. ПРИМИТИВЫ РАБОТЫ С ПАМЯТЬЮ

  Заполнение массива шаблоном

// libpub

void *memfill(void * buf, size_t size, const void * pat, size_t patsize);
    // fill array with pattern
    // return 1st argument

  Удаление элемента из массива

// libpub

void *memdel(void * p, size_t size, size_t n);
    // delete element from array
    // return 1st argument

  Вставка элемента в массив

// libpub

void *memins(void * tgt, size_t tgtsize, const void * src, size_t srcsize);
    // insert bytes at the beginning of memory block
    // Return: 1st argument

// To  insert  a new element at the ith position of an array, one might do
// the following.

       int new, array[10];

       memins(array+i, (10-i-1)*sizeof(array[0]), &new, sizeof(new));

// Please note that the above code carefully avoids the trap of moving the
// last element of the array past the end of the array.

  Поиск шаблона в памяти

    Поиск шаблона в памяти
        В прямом порядке
        В обратном порядке

// libpub

void *memmem(const void *, size_t, const void * needle, size_t needlelen);
    // search substring from start of block
    // return: pointer to first block of match or NULL

// libpub

void *memrmem(const void * v, size_t size, const void * pat, size_t patsize);
    // Find last occurence of pattern within memory block v
    // Return: pointer to first block of match or NULL

Реально алгоритмы для поиска шаблонов в памяти мы будем рассматривать
в секции 70.2.6.1.1. АЛГОРИТМЫ НА СТРОКАХ

  Паралелизация поиска шаблона в памяти

  Обмен местами блоков памяти

Кроме того это обмен местами двух элементов массива или групп элементов
одинаковой длинны.

// libpub

void memswap(void *, void *, size_t);

  Рандомизация массива

// libpub

void *memshuffle(void * block, size_t elsize, size_t elnum);
    // make array of random order
    // return 1st argument

  Обращение массива

Собственно применение кроме обращения массива, еще и смена endian
(вырожденный случай - elsize = 1).

// libpub

void*	memrev(void* block, size_t elsize, size_t elnum);

  Паралелизация обращения массива

void *memarrfill(void *arr, size_t elsize, size_t nelem)
{
    assert(arr != NULL);
    assert(elsize > 0);

    if (nelem > 0)
        memfill((char*)arr+elsize, (nelem-1)*elsize, arr, elsize);
    return arr;
}

void memisort(void *, size_t, size_t, const void *,
        int (*)(const void *, const void *));

  Рефлексия массивов

Полезные макросы

//stdlib.h
#define countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))

Но не пытайтесь это сделать с TYPE* - результат может шокировать.

  Сортировка и поиск в массивах

На тему сортировки и поиска читайте секции:
70.3.2. АЛГОРИТМЫ СОРТИРОВКИ
70.3.3. АЛГОРИТМЫ ПОИСКА

  Сортировка массива

// stdlib.h
void qsort(
   void *base,
   size_t num,
   size_t width,
   int (__cdecl *compare )(const void *, const void *)
);

void qsort_s(		// with context
   void *base,
   size_t num,
   size_t width,
   int (__cdecl *compare )(void *, const void *, const void *),
   void * context
);

    int  array[20];

    ...

    qsort(&array[0],
          20,
          sizeof(int),
          cmp_int);		// читай ниже cmp_int из libpub

  Поиск в массиве

Поиск в неотсортированном массиве:

Поиск в сортированном массиве:

// stdlib.h
void* bsearch(
   const void *key,
   const void *base,
   size_t num,
   size_t width,
   int ( __cdecl *compare ) ( const void *, const void *)
);

void* bsearch_s( 		// with context
   const void *key,
   const void *base,
   size_t num,
   size_t width,
   int ( __cdecl *compare ) ( void *, const void *, const void *),
   void * context
);

    int  array[20];
    ....
    int  key = 5;

    int* pos = (int *) bsearch(&key,
                       &array[0],
                       20,
                   sizeof(int),
                   cmp_int);
    if (pos == NULL)
    {
        printf("Not found\n");
    } else {
        printf("Found at position %d\n", (int) (pos - (&array[0])));
    }

// libpub - наличие функций сравнения для стандартных типов данных

int cmp_char(const void *, const void *);
int cmp_short(const void *, const void *);
int cmp_int(const void *, const void *);
int cmp_long(const void *, const void *);

int cmp_schar(const void *, const void *);

int cmp_uchar(const void *, const void *);
int cmp_ushort(const void *, const void *);
int cmp_uint(const void *, const void *);
int cmp_ulong(const void *, const void *);

int cmp_float(const void *, const void *);
int cmp_double(const void *, const void *);
int cmp_ldouble(const void *, const void *);

int cmp_charptr(const void *, const void *);

  Паралелизация операций для массива

Вставка элемента (не в конце)
    Паралелизация на пересылке памяти    O(n/p)

Удаление элемента (не в конце)
    Паралеллизация на пересылке памяти   O(n/p)

Поиск элемента в неотсортированном массиве
    Паралельный поиск элемента O(n/p)

Сортировка массива
    Паралелизация на упорядочивании подмассивов
    (и для больших случаев на промежуточных merge)

  Примитивы для работы с двумерными массивами

С двумерными массивами мы получаем целую кучу новых операций:

    Вставить
        столбец
        строку

    Удалить
        столбец
        строку

    Поменять местами
        столбцы
        строки

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

  STL обертка для массива фиксированной длинны

Появилась в TR1

namespace tr1
{

template<class _Ty,size_t _Size>
class array
{
public:
    enum {_EEN_SIZE = _Size};
    typedef array<_Ty, _Size> _Myt;
    typedef _Ty value_type;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef _Ty *pointer;
    typedef const _Ty *const_pointer;
    typedef _Ty& reference;
    typedef const _Ty& const_reference;

    typedef _Array_iterator<_Ty, _Size> iterator;
    typedef _Array_const_iterator<_Ty, _Size> const_iterator;

    typedef _STD reverse_iterator<iterator> reverse_iterator;
    typedef _STD reverse_iterator<const_iterator> const_reverse_iterator;

    void assign(const _Ty& _Value)
        {	// assign value to all elements
            _STD fill_n(_Elems, _Size, _Value);
        }

    void fill(const _Ty& _Value)
        {	// assign value to all elements
            _STD fill_n(_Elems, _Size, _Value);
        }

    void swap(_Myt& _Other)
        {	// swap contents with _Other
            _Swap_ranges(_STD addressof(_Elems[0]),
            _STD addressof(_Elems[0]) + _Size, _STD addressof(_Other._Elems[0]));
        }

    void swap(_Myt&& _Other)
        {	// swap contents with _Other
            _Move(_Other.begin(), _Other.end(), begin());
        }

    iterator begin()
        {	// return iterator for beginning of mutable sequence
            return (iterator(_STD addressof(_Elems[0]), 0));
        }

    const_iterator begin() const
        {	// return iterator for beginning of nonmutable sequence
            return (const_iterator(_STD addressof(_Elems[0]), 0));
        }

    iterator end()
        {	// return iterator for end of mutable sequence
            return (iterator(_STD addressof(_Elems[0]), _Size));
        }

    const_iterator end() const
        {	// return iterator for beginning of nonmutable sequence
            return (const_iterator(_STD addressof(_Elems[0]), _Size));
        }

    reverse_iterator rbegin()
        {	// return iterator for beginning of reversed mutable sequence
            return (reverse_iterator(end()));
        }

    const_reverse_iterator rbegin() const
        {	// return iterator for beginning of reversed nonmutable sequence
            return (const_reverse_iterator(end()));
        }

    reverse_iterator rend()
        {	// return iterator for end of reversed mutable sequence
            return (reverse_iterator(begin()));
        }

    const_reverse_iterator rend() const
        {	// return iterator for end of reversed nonmutable sequence
            return (const_reverse_iterator(begin()));
        }

 #if _HAS_CPP0X
    const_iterator cbegin() const
        {	// return iterator for beginning of nonmutable sequence
            return (((const _Myt *)this)->begin());
        }

    const_iterator cend() const
        {	// return iterator for end of nonmutable sequence
            return (((const _Myt *)this)->end());
        }

    const_reverse_iterator crbegin() const
        {	// return iterator for beginning of reversed nonmutable sequence
            return (((const _Myt *)this)->rbegin());
        }

    const_reverse_iterator crend() const
        {	// return iterator for ebd of reversed nonmutable sequence
            return (((const _Myt *)this)->rend());
        }
 #endif /* _HAS_CPP0X */

    size_type size() const
        {	// return length of sequence
            return (_Size);
        }

    size_type max_size() const
        {	// return maximum possible length of sequence
            return (_Size);
        }

    bool empty() const
        {	// test if sequence is empty
            return (_Size == 0);
        }

    reference at(size_type _Pos)
        {	// subscript mutable sequence with checking
            if (_Size <= _Pos)
                _Xran();
            return (_Elems[_Pos]);
        }

    const_reference at(size_type _Pos) const
        {	// subscript nonmutable sequence with checking
            if (_Size <= _Pos)
                _Xran();
            return (_Elems[_Pos]);
        }

    reference operator[](size_type _Pos)
        {	// subscript mutable sequence
            __analysis_assume(_Pos < _Size);

            return (_Elems[_Pos]);
        }

    const_reference operator[](size_type _Pos) const
        {	// subscript nonmutable sequence
            __analysis_assume(_Pos < _Size);
            return (_Elems[_Pos]);
        }

    reference front()
        {	// return first element of mutable sequence
            return (_Elems[0]);
        }

    const_reference front() const
        {	// return first element of nonmutable sequence
            return (_Elems[0]);
        }

    reference back()
        {	// return last element of mutable sequence
            return (_Elems[_Size - 1]);
        }

    const_reference back() const
        {	// return last element of nonmutable sequence
            return (_Elems[_Size - 1]);
        }

    _Ty *data()
        {	// return pointer to mutable data array
            return (_Elems);
        }

    const _Ty *data() const
        {	// return pointer to nonmutable data array
            return (_Elems);
        }

    __declspec(noreturn) void _Xran() const
        {	// report an out_of_range error
            _STD _Xout_of_range("invalid array<T, N> subscript");
        }

        _Ty _Elems[_Size == 0 ? 1 : _Size];

};	// class array

}	// namespace tr1

Кроме этого в TR1 есть перегруженный вариант для длинны = 0
template<class _Ty> class array<_Ty, 0>

  Контейнер для массива

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

По сравнению с массивов у контейнера появляется новое свойство - емкость
И соответсвенно новый набор операций

    Изменение размера контейнера

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

Типовое устройство контейнера:

Вообще говоря есть 2 основных варианта:
1) держать pointer, и числовые capacity и size
2) держать 3 pointers

Частично заполненный массив:

Полностью заполненный массив:

Полностью пустой массив:

Совсем пустой массив:

// STL <vector>

template <class T, class Allocator = allocator<T>> class vector
{
public:

    typedef Allocator allocator_type;

    typedef	T   value_type;
    typedef T*  pointer;
    typedef T&  reference;
    typedef const T& const_reference;

    typedef int size_type;
    typedef int difference_type;

    typedef T*	  iterator;
    typedef const T*  const_iterator;
    typedef T*	  reverse_iterator;
    typedef const T*  const_reverse_iterator;

    vector();
    vector(size_type count, const T& val);
    vector(size_type count, const T& val, const Allocator&);
    vector(const vector<T, Allocator>& right);
    explicit  vector(const Allocator&);
    explicit  vector(size_type count);
        template <class InputIterator> vector(InputIterator first, InputIterator last);
    template <class InputIterator> vector(InputIterator first, InputIterator last,
                          const Allocator&);

    ~vector();

    void assign(size_type count, const T& val);
    template <class InputIterator>
    void assign(InputIterator first, InputIterator last);

    reference       at(size_type index);
    const_reference at(size_type index) const;

    reference	operator[](size_type pos);
    const_reference operator[](size_type pos) const;

    iterator	 	begin();
    const_iterator   	begin() const;
    iterator	 	end();
    const_iterator   	end() const;
    reverse_iterator 	rbegin();
    const_reverse_iterator  rbegin() const;
    reverse_iterator	rend();
    const_reverse_iterator  rend() const;

    size_type      capacity() const;
    bool	       empty() const;
    size_type      max_size() const;
    size_type      size() const;

    void	       reserve(size_type count);
    void	       resize(size_type newsize);
    void	       resize(size_type newsize, const T& val);

    void	       clear();		// erase all elements of vector
    iterator  erase(iterator where);
    iterator  erase(iterator first, iterator last);
    iterator  insert(iterator where, const T& val);
    void	  insert(iterator where, size_type count, const T& val);
    template <class InputIterator>
    void insert(iterator where, InputIterator first, InputIterator last);

    void	  push_back(const T& val);
    void	  pop_back();

    void    swap(vector<T,Allocator>& right);
    friend void swap(vector<T,Allocator>& left, vector<T,Allocator>& right);

    Allocator get_allocator() const;

    reference  front();           	// reference to 1st element
    const_reference front() const;

// А теперь собственно что лежит внутри:
private:
    T*  	    objects;
    size_type   size;
    size_type   capacity;
};

template <class T, class A>
void swap(vector<T,A>& l, vector<T,A>& r);

template <class T, class A>
bool operator == (const vector<T,A>& l, const vector<T,A>& r);

template <class T, class A>
bool operator != (const vector<T,A>& l, const vector<T,A>& r);

template <class T, class A>
bool operator > (const vector<T,A>& l, const vector<T,A>& r);
template <class T, class A>

bool operator >= (const vector<T,A>& l, const vector<T,A>& r);

template <class T, class A>
bool operator < (const vector<T,A>& l, const vector<T,A>& r);

template <class T, class A>
bool operator <= (const vector<T,A>& l, const vector<T,A>& r);

Немного об имплементации:

// Индексация:

    T& operator[](size_type pos)
    {
        return  &objects[pos];
    }

    const T& operator[](size_type pos) const
    {
        return	&objects[pos];
    }

// Получение итераторов:

    iterator begin()
    {
        return	&objects[0];
    }

    const_iterator begin() const
    {
        return	&objects[0];
    }

    iterator end()
    {
        return  &objects[size];
    }

    const_iterator  end() const
    {
        return	&objects[size];
    }

    iterator rbegin()
    {
        return	&objects[size-1];
    }

    iterator rend()
    {
        return	&objects[-1];
    }

// Статистика
    bool empty() const
    {
        return	size == 0;
    }

    size_type   size() const       { return size;     }
    size_type   capacity() const   { return capacity; }

    bool operator == (const vector<T,A>& l, const vector<T,A>& r);
    {
        return l.size() == r.size() && equal(l.begin(), l.end(), r.begin());
    }

  Индексаторы

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

Разница между встроенными типами и индексаторами

    a[i]     =>   *(a + i)

C++ для встроенных типов:
    a[5]	// ok
    5[a]	// ok

C++ для типов с перегруженной индексацией

    a[5]	// ok
    5[a]	// error

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

Как правило - кидаем exception

T&  operator[](size_type pos)
{
    if ((pos < 0) || (pos >= size))
    {
        throw std::range_error("Array range error");
    }
    return	&objects[pos];
}

  Поддержка отрицательных индексов

Если обычный массив  [0..max)
То отрицательные индексы [-1..-max]

T& operator[] (int pos)
{
    if (pos < 0) pos += size;
    return	&objects[pos];
}

  Использование другого диапазона для индексации

Вместо    [0..max)
например  [N..M)

T& operator[] (size_type pos)
{
    pos -= pos_skew;
    return	&objects[pos];
}

  Поддержка многомерных контейнеров

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

Оператор индексации контейнера возвращает по значению proxy-class
который содержит оператор индексации для второго индекса.

template <class T> class A2
{
public:
    A2(int dim1, int dim2);

    // возможность индексировать через круглые скобки
    T& operator()(int idx1, int idx2);
  const T& operator()(int idx1, int idx2) const;

    // возможность индексировать через набор квадратных скобок
    class A1
    {
    public:
        A1(A2& base, int idx1);

        T&  operator[] (int idx2);
      const T&  operator[] (int idx2) const;
        ...
    };

        A1  operator[] (int idx1);
        const	A1  operator[] (int idx1) const;
};

  Различение чтения и записи

Собственно делается через proxy object.
Но существуют и подводные камни. Например вы можете сделать:
    a[i] = val;
    var  = a[i];

но такую вещь как:

    a[i].somefunction()

вы сделать не можете, если только не создадите соответсвующий
wrapper в TProxy.

template <class T> class SmartArray
{
public:
    class TProxy
    {
    public:
        TProxy(SmartArray<T>& array, int idx);
        TProxy& operator=(const TProxy&);

        // собственно разделение доступа

        Tproxy& operator=(T value);	// как lvalue
        operator T() const;             // как rvalue

        // получение указателя на элемент массива
        // понятно что по указателю мы не разделим R/W

              T* operator&();
        const T* operator&() const;

    private:
        SmartArray<T>&  array;
        int		index;
    };

    const TProxy operator[] (int index) const;
    TProxy       operator[] (int index)
    {
        return TProxy(const_cast<SmartArray<T>&>(*this), index);
    }
};

  Реализация прозрачных срезов

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

// в этом примере класс для простых срезов в одномерном C<T>

template <class T, class C<T> > class slice
{
public:
    slice(C<T>& base, int endidx);				   //   end::1
    slice(C<T>& base, int startidx, int endidx);		   // start:end:1
    slice(C<T>& base, int startidx, int endidx, int stepidx);  // start:end:step

    int size()
    {
        return (endidx - startidx) / stepidx + 1;
    }

    T& operator[](int index)
    {
        int  baseidx = startidx + stepidx * index;
        return	base[baseidx];
    }

private:
    C<T>&  	   base;
    int	   startidx;
    int	   endidx;
    int	   stepidx;
};


70.2.5.1. БИТОВЫЕ МАССИВЫ (BITMAP)

THIS SECTION IS UNDER CONSTRUCTION

  Bitmap

Bitmap - массив битов.
Каждый бит может находиться только в 2х состояниях: 0 и 1 (занято/cвободно).

Первое на что надо обратить внимание, это что bitmap
могут достигать гигантских объемов, поэтому надо уметь обрабатывать
как внутренние (то есть лежащие в памяти), так и внешние bitmaps.

Например для NTFS тома размером в 4TB, и размером кластера 4KB
размер Bitmap для свободных и занятых кластеров будет 1GB битов,
то есть 128MB. И с ростом носителей будет только расти.

RTL для bitmap в полном объеме:

    Установить бит
    Сбросить   бит
    Инвертировать бит
    Узнать значение бита

    Установить группу битов
    Сбросить группу битов
    Инвертировать группу битов

    Установить все биты в Bitmap
    Сбросить все биты в Bitmap

    Количество сброшенных/установленых битов
        в bitmap
        в диапазоне

    Проверка являются ли все биты
        сброшенными
        установленными
            в bitmap
            в диапазоне

    Найти биты
         установленные
         сброшенные
        длинной  1
        длинной	 N
            в bitmap
                начиная с позиции
            в диапазоне
                c начала
                с конца
         (и после нахождения инвертировать).

 Windows

VOID  RtlInitializeBitMap(
        IN PRTL_BITMAP  BitMapHeader,
        IN PULONG  BitMapBuffer,
        IN ULONG  SizeOfBitMap
        );

typedef struct _RTL_BITMAP {
  // opaque
} RTL_BITMAP;

typedef RTL_BITMAP *PRTL_BITMAP;

VOID
RtlInitializeBitMap (
    IN PRTL_BITMAP BitMapHeader,
    IN PULONG BitMapBuffer,
    IN ULONG SizeOfBitMap
    )
{
    BitMapHeader->SizeOfBitMap = SizeOfBitMap;
    BitMapHeader->Buffer = BitMapBuffer;
}

  Установить бит

VOID    RtlSetBit(
        PRTL_BITMAP  BitMapHeader,
        ULONG  BitNumber
        );

  Сбросить бит

VOID    RtlClearBit(
        PRTL_BITMAP  BitMapHeader,
        ULONG  BitNumber
        );

  Получить значение бита

BOOLEAN  RtlTestBit(
        PRTL_BITMAP  BitMapHeader,
        ULONG  BitNumber
        );

  Инвертировать бит

  Установить группу битов

VOID  RtlSetBits(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  StartingIndex,
        IN ULONG  NumberToSet
        );

  Сбросить группу битов

VOID  RtlClearBits(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  StartingIndex,
        IN ULONG  NumberToClear
        );

  Инвертировать группу битов

  Установить все биты

VOID  RtlSetAllBits(
        IN PRTL_BITMAP  BitMapHeader
        );

VOID  RtlSetAllBits(IN PRTL_BITMAP  BitMapHeader)
{
    RtlFillMemoryUlong( BitMapHeader->Buffer,
                        ((BitMapHeader->SizeOfBitMap + 31) / 32) * 4,
                        0xffffffff
                      );
}

  Сбросить все биты

VOID  RtlClearAllBits(
        IN PRTL_BITMAP  BitMapHeader
        );

VOID  RtlClearAllBits(IN PRTL_BITMAP  BitMapHeader)
{
    RtlZeroMemory( BitMapHeader->Buffer,
                   ((BitMapHeader->SizeOfBitMap + 31) / 32) * 4
                 );
}

  Получить количество установленных бит

ULONG  RtlNumberOfSetBits(
        IN PRTL_BITMAP  BitMapHeader
        );

  Получить количество сброшенных бит

ULONG  RtlNumberOfClearBits(
        IN PRTL_BITMAP  BitMapHeader
        );

  Проверить что все биты в группе сброшены

BOOLEAN   RtlAreBitsClear(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  StartingIndex,
        IN ULONG  Length
        );

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

BOOLEAN   RtlAreBitsSet(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  StartingIndex,
        IN ULONG  Length
        );

  Найти последовательность сброшенных бит

ULONG  RtlFindClearBits(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  NumberToFind,
        IN ULONG  HintIndex
        );

  Найти последовательность установленных бит

ULONG  RtlFindSetBits(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  NumberToFind,
        IN ULONG  HintIndex
        );

  Найти последовательность сброшенных бит и инвертировать их

ULONG  RtlFindClearBitsAndSet(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  NumberToFind,
        IN ULONG  HintIndex
        );

  Найти последовательность установленных бит и инвертировать их

ULONG  RtlFindSetBitsAndClear(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  NumberToFind,
        IN ULONG  HintIndex
        );

Другие примитивы

ULONG  RtlCheckBit(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  BitPosition
        );

ULONG  RtlFindClearRuns(
        IN PRTL_BITMAP  BitMapHeader,
        OUT PRTL_BITMAP_RUN  RunArray,
        IN ULONG  SizeOfRunArray,
        IN BOOLEAN  LocateLongestRuns
        );

ULONG  RtlFindFirstRunClear(
        IN PRTL_BITMAP  BitMapHeader,
        OUT PULONG  StartingIndex
        );

ULONG  RtlFindLastBackwardRunClear(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  FromIndex,
        OUT PULONG  StartingRunIndex
        );

ULONG  RtlFindLongestRunClear(
        IN PRTL_BITMAP  BitMapHeader,
        OUT PULONG  StartingIndex
        );

ULONG  RtlFindNextForwardRunClear(
        IN PRTL_BITMAP  BitMapHeader,
        IN ULONG  FromIndex,
        OUT PULONG  StartingRunIndex
        );

Очень сильно помогает наличие аппаратной реализации в CPU
функции POPCNT (Population Count).

x86:
    POPCNT	r16,r/m16
    POPCNT	r32,r/m32
    POPCNT	r64,r/m64	; x64

    POPCNT	dest, src

        dest = POPCNT(1, src);
        ZF = 1 if src == 0;

Intel/Microsoft C++ compiler intrinsic:

    int	_mm_popcnt_u32(unsigned int x);		// x86
    __int64 _mm_popcnt_u64(unsigned __int64 x);	// x86,x64

Как правило для убыстрения реализации используют дополнительные таблицы с данными:

//
//  Lookup table that tells how many contiguous bits are clear (i.e., 0) in
//  a byte
//
CONST CCHAR RtlpBitsClearAnywhere[] =
         { 8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,
           4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
           5,4,3,3,2,2,2,2,3,2,2,2,2,2,2,2,
           4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2,
           6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,
           4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
           5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,
           4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
           7,6,5,5,4,4,4,4,3,3,3,3,3,3,3,3,
           4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2,
           5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,
           4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
           6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,
           4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
           5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,
           4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,0 };

//
//  Lookup table that tells how many contiguous LOW order bits are clear
//  (i.e., 0) in a byte
//
CONST CCHAR RtlpBitsClearLow[] =
          { 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
            4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 };

//
//  Lookup table that tells how many contiguous HIGH order bits are clear
//  (i.e., 0) in a byte
//
CONST CCHAR RtlpBitsClearHigh[] =
          { 8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,
            3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
            2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
            2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
            1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
            1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
            1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
            1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

//
//  Lookup table that tells how many clear bits (i.e., 0) there are in a byte
//
CONST CCHAR RtlpBitsClearTotal[] =
          { 8,7,7,6,7,6,6,5,7,6,6,5,6,5,5,4,
            7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
            7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
            6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
            7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
            6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
            6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
            5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
            7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
            6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
            6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
            5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
            6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
            5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
            5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
            4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };

//
//  Bit Mask for clearing and setting bits within bytes.  FillMask[i] has the first
//  i bits set to 1.  ZeroMask[i] has the first i bits set to zero.
//

static CONST UCHAR FillMask[] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
static CONST UCHAR ZeroMask[] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 };

  STL bitset

В STL есть шаблон для работы с bitset.
Он использует proxy-индексатор с разделением чтения и записи для
доступа к отдельным битам по индексу.

template <size_t N> class bitset
{
public:

    typedef bool element_type;

    class reference
    {
        friend class bitset<N>;
    public:
        reference& operator=(bool val);
        reference& operator=(const reference& ref);
        bool operator~() const;
        operator bool() const;
        reference& flip();
    };

    bitset();
    bitset(unsigned long val);

    template<class CharType, class Traits, class Allocator>
        explicit bitset(const basic_string<CharType, Traits, Allocator>& _Str,
                        typename basic_string<CharType, Traits, Allocator>::size_type _Pos = 0);

    template<class CharType, class Traits, class Allocator >
    explicit bitset(const basic_string<CharType, Traits, Allocator>& _Str,
                 typename basic_string<CharType, Traits, Allocator>::size_type _Pos = 0,
                    typename basic_string<CharType, Traits, Allocator>::size_type _Count);

    bool 	any() const;
    bool	none() const;
    size_t  count() const;
    size_t  size()  const;
    bool	test(size_t pos) const;

    bitset<N>&  flip();
    bitset<N>&  flip(size_t pos);

    bitset<N>&  reset();
    bitset<N>&  reset(size_t pos);

    bitset<N>&  set();
    bitset<N>&  set(size_t pos, bool val = true);

    unsigned long to_ulong( ) const;

    template<class CharType, class Traits, class Alloc>
       basic_string<CharType, Traits, Alloc> to_string ( ) const;

    bool operator == (const bitset<N>& r) const;
    bool operator != (const bitset<N>& r) const;

    bitset<N>& operator &= (const bitset<N>& r);
    bitset<N>& operator |= (const bitset<N>& r);
    bitset<N>& operator ^= (const bitset<N>& r);
    bitset<N>& operator <<= (size_t pos);
    bitset<N>& operator >>= (size_t pos);

    bitset<N> operator~() const;
    bitset<N> operator<<(size_t pos) const;
    bitset<N> operator>>(size_t pos) const;

    bool operator[](size_t pos) const;
    reference operator[] (size_t pos);

};

template <size_t size>
    bitset<size> operator&(const bitset<size>& l, const bitset<size>& r);
template <size_t size>
    bitset<size> operator^(const bitset<size>& l, const bitset<size>& r);
template <size_t size>
    bitset<size> operator|(const bitset<size>& l, const bitset<size>& r);

  STL vector

template <class A> class vector<bool, A>
{
public:
    typedef  A    allocator_type;
    typedef  bool value_type;

    class	reference
    {
        friend class vector<bool, A>;
        reference() : Ptr(0), Mask(0) { }
    public:
        reference& operator=(const reference& x);
        reference& operator=(bool x);
        void flip();
        bool operator ~ () const;
        operator bool() const;
    private:
        unsigned int*  Ptr;
        unsigned int   Mask;

    };
    typedef const reference const_reference;

    class const_iterator
    {
    public:
        const_iterator();
        const_iterator(size_t O, const unsigned int *P);
        const_iterator(const iterator& _X);

        const_reference operator*() const;
        const_iterator& operator++();
        const_iterator  operator++(int);
        const_iterator& operator--();
        const_iterator  operator--(int);
        const_iterator& operator+=(difference_type n);
        const_iterator& operator-=(difference_type n);
        const_iterator  operator+(difference_type n) const;
        const_iterator  operator-(difference_type n) const;
        difference_type operator-(const const_iterator x) const;
        const_reference operator[](difference_type n) const;
        bool operator==(const const_iterator& x) const;
        bool operator!=(const const_iterator& x) const;
        bool operator<(const const_iterator&  x) const;
        bool operator>(const const_iterator&  x) const;
        bool operator<=(const const_iterator& x) const;
        bool operator>=(const const_iterator& x) const;
    protected:
        void Dec();
        void Inc();
        size_t Off;
        unsigned int * Ptr;
    };

    class iterator : public const_iterator
    {
    public:
        iterator();
        iterator(size_t _O, _Vbase *_P);
        reference operator*() const;
        iterator& operator++();
        iterator operator++(int);
        iterator& operator--();
        iterator operator--(int);
        iterator& operator+=(difference_type _N);
        iterator& operator-=(difference_type _N);
        iterator operator+(difference_type _N) const;
        iterator operator-(difference_type _N) const;
        difference_type operator-(const iterator _X) const;
        reference operator[](difference_type _N) const;
        bool operator==(const iterator& _X) const;
        bool operator!=(const iterator& _X) const;
        bool operator<(const iterator& _X) const;
        bool operator>(const iterator& _X) const;
        bool operator<=(const iterator& _X) const;
        bool operator>=(const iterator& _X) const
    };

    // В общем практически тоже самое что для класса вектор
    // за исключением специальных реализаций для reference
    // и итераторов

    void flip();
    static void swap(reference& x, reference& y);
};

Теперь об реализации Reference:

reference() : Mask(0), Ptr(0) {}

reference(size_t O, unsigned int * P)
            : _Mask((unsigned int)1 << O), Ptr(P) {}

operator = (bool val)
{
    if (v)
    {
        *Ptr |= Mask;
    } else {
        *Ptr &= ~Mask;
    }
    return (*this);
}

operator bool()
{
    return (*Ptr & Mask) != 0;
}

bool operator~()
{
    return !bool(*this);
}

Собственно реализация внутри const_iterator:

void Inc()
{
    if (Off < VBITS - 1)
    {
        ++Off;
    } else {
        Off = 0;
        ++Ptr;
    }
}

void Dec()
{
    if (Off != 0)
    {
        --Off;
    } else {
        Off = VBITS - 1;
        --Ptr;
    }
}

const_reference operator*() const
{
    return (const_reference(Off, Ptr));
}

const_reference operator[](difference_type n) const
{
    return (*(*this + n));
}

const_iterator& operator++()
{
    Inc();
    return (*this);
}

const_iterator operator++(int)
{
    const_iterator Tmp = *this;
    Inc();
    return (Tmp);
}

const_iterator& operator--()
{
    Dec();
    return (*this);
}

const_iterator operator--(int)
{
    const_iterator Tmp = *this;
    Dec();
    return (Tmp);
}

const_iterator& operator+=(difference_type n)
{
    Off += n;
    Ptr += Off / VBITS;
    Off %= VBITS;
    return (*this);
}

const_iterator& operator-=(difference_type n)
{
    return (*this += -n);
}

const_iterator operator+(difference_type n) const
{
    const_iterator Tmp = *this;
    return (Tmp += n);
}

const_iterator operator-(difference_type n) const
{
    const_iterator Tmp = *this;
    return (Tmp -= n);
}

difference_type operator-(const const_iterator x) const
{
    return (VBITS * (Ptr - x.Ptr)
            + (difference_type)Off
            - (difference_type)x.Off);
}

bool operator==(const const_iterator& x) const
{
    return (Ptr == x.Ptr && Off == x.Off);
}

bool operator!=(const const_iterator& x) const
{
    return (!(*this == x));
}

bool operator<(const const_iterator& x) const
{
    return (Ptr < x.Ptr || Ptr == x.Ptr && Off < x.Off);
}

bool operator>(const const_iterator& x) const
{
    return (x < *this);
}

bool operator<=(const const_iterator& x) const
{
    return (!(x < *this));
}

bool operator>=(const const_iterator& x) const
{
    return (!(*this < x));
}


70.2.6. СТРОКИ

THIS SECTION IS UNDER CONSTRUCTION

                Строки
        (по хранимым символам)
      /        |        \      \
         8 bit	 Multibyte 16-bit   32-bit
     ANSI		   UNICODE  UNICDOE

Имейте в виду что строки могут быть в различных форматах:
        8-bit
        Multibyte  (UTF-8 это тоже пример мультибайт)
        16-bit Unicode (UCS-2)
        Unicode UTF-16
        Unicode UCS-4

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

  Способы хранения строк

              Строки
      (по способу организации хранения)
       /          |         \
    Asciiz      Pascal      прочие
    Unicodez
      (короче 0-ended)

Asciiz самый популярный вариант для строк. Обусловлено это в первую очередь языком C, который
использовался для создания практически всех основных операционных систем - в результате чего
большинство API ориентировано на zero-ended строки.

  ASCIIZ-строки

    +---+---+---+---+---+---+---+
    |'S'|'T'|'R'|'I'|'N'|'G'| 0 |
    +---+---+---+---+---+---+---+
    Строка заканчивается символом с кодом 0.

Здесь пример байтовой строки, но строка может быть и широкой (т.е. содержать 16-битовые символы
и оканчиваться 16-битовым символом с кодом 0), так и очень широкой (32-битовые символы).

  Pacal-строки

    +---+---+---+---+---+---+---+
    | 6 |'S'|'T'|'R'|'I'|'N'|'G'|
    +---+---+---+---+---+---+---+
    Первый байт (или слово) строки содержит ее длинну.

Строки фиксированной длинны.

{ Delphi }

type ShortString = string[Const];
type AnsiChar    = #0 .. #255;
type WideChar    = #0 .. #65535;

type AnsiString = record
    Capacity : LongWord;
    RefCount : LongWord;
    Length   : LongWord;
    Data	 : array[1 .. Length+1] of AnsiChar;
end;

type WideString = record   	{ PARTIAL }
    Length   : LongInt;
    Data	 : array[1 .. Length+1] of WideChar;
end;

type  PChar       = ^Char;
type  PWideChar   = ^WideChar;

  UNICODE_STRING

Бывают и более страшные структуры.
например UNICODE_STRING из Windows NT/2000/XP DDK

    typedef struct _UNICODE_STRING {
      USHORT  Length;   			// Текущая длинна
      USHORT  MaximumLength;		// Максимально возможная длинна
                        // для текущего буфера
      PWSTR  Buffer;			// Указатель на буфер
                        // Строка в буфере не оканчивается нулем
    } UNICODE_STRING *PUNICODE_STRING;

    +---+---+
    |   6   | Length
    +---+---+
    |   8   | MaximumLength
    +---+---+---+---+     +---+---+---+---+---+---+---+---+
    |   Buffer     o|---->|'S'|'T'|'R'|'I'|'N'|'G'| ? | ? |
    +---+---+---+---+     +---+---+---+---+---+---+---+---+

  BSTR

OLE использует BSTR строки

Особенности:
    собственно сами строки как правило wide
    длинна указывается в байтах (не считая trailing zero)
    Trailing zero всегда присудствует
    Строка может содержать нулевые символы

  Прочие варианты

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

    +------+    +-------+       +-------+
    |     o|--->|      o|------>|      X|
    +------+    +---+---+	    +---+---+
            |'S'|'T'|	    |'N'|'G'|
            +---+---+	    +---+---+
            |'R'|'I'|	    | 0 | ? |
            +---+---+	    +---+---+

struct _string_page
{
    struct _string_page* Next;
    char   Data[FIXED_SIZE];
};

  Обеспечение мультипоточной безопасности

Thread-безопасные операции со строками

    Read-only строковые объекты
    Блокирование строки на время операции
        работает только если данные выбираются вовне
        и не происходит обращение к ним in-place

Как извество паралельным чтением данные не испортить. Поэтому есть тенденция
делать строковые объекты неизменяемыми
например есть классы:

    String		- неизменяемый
              (строка живет именно в нем)
    StringBuffer    - временный изменяемый чисто для операций
                  (сответсвенно используется чисто локально для построения строки)

Кроме того в структуре строки держат счетчик ссылок и используют технологию
COW (Copy-on-Write).


70.2.6.1. КОНЦЕТУАЛЬНЫЙ RTL ДЛЯ СТРОК

  Концептуальный RTL для строк

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

Вообще говоря структура наиболее общего вида:
    POINTER		Buffer
    INTEGER		CurrentLength
    INTEGER		AllocatedLength
    INTEGER		Locale
    INTEGER		ReferenceCount	что бы делать COW
    LOCK_T		Lock		для thread safe работы со строкой
    FLAG		LockedBuffer

Проблемы
    Locale + Multibyte
Если вы планируете все писать с нуля - закладывайтесь на UTF-8
и пакуйте символы по максимуму.
(даже с Unicode - вы уже получите Unicode Endian проблему).

NOTE

Бойтесь char в C++.
Реально в C как бы существует 3 типа char:
    signed char
    unsigned char
    char		// трактуется как signed или unsigned в зависимости от ключей
В С++ char трактуется как signed, в результате имеем проблемы с проверками символов
больших чем 0x7f:

    char* s;
    ...
    if (*s == 0xf0)
    {
        ...
    }

Компилятор понимает что 0xf0 не представимо в signed char, значит проверка закончиться неудачей
всегда, получаем:

    char * s;
    ...
    if (0)     		// и этот код вообще удаляется
    {
        ...
    }

  Создание/удаление строки

ASCIIZ:
    собственно прописать символ с кодом 0 в начале - типа пустая строка

Pascal:
    поставить размер равный 0

UNICODE_STRING:
    поставить буфер, размер, аллоцированную длинну в 0

    UNICODE_STRING   ucs;

    RtlZeroMemory(&ucs, sizeof(UNICODE_STRING));

  Инициализация строки

    Инициализация строки
        из другой строки
        из строковой константы

ASCIIZ:
    присваиваем указатель (так как char*)
    используем strcpy для копирования в нужный нам буфер

UNICODE_STRING:

VOID
  RtlInitUnicodeString(				   // ставит Buffer на source string
    IN OUT PUNICODE_STRING  DestinationString,	   // заполняет длинну
    IN PCWSTR  SourceString
    );

  Длинна строки

    Вычисление длинны строки
        strlen
            multibyte version
                в символах
                в байтах

size_t	strlen(const char * s);
size_t  strnlen(const char* s, size_t number_of_elements);

size_t  wcslen(const wchar_t* s);
size_t  wcsnlen(const wchar_t * s, size_t number_of_elements);

size_t  mbslen(const unsigned char* s);		// Return  -1 if invalid character in string
size_t  mbsnlen(const unsigned char* s, size_t number_of_elements);

_tcslen
_tcsnlen
_tcsnbcnt

// C style strings
size_t  strlen(const char* s)
{
    size_t len = 0;
    while (*s++ != '\0') len++;
    return	len;
}

size_t strlen (const char* str)
{
        const char *eos = str;
        while( *eos++ ) ;
        return( (int)(eos - str - 1) );
}

size_t  strnlen(const char* s, size_t noe)
{
    size_t len = 0;
    while (*s++ != '\0')
    {
        len++;
        if (len == noe) return len;
    }
    return	len;
}

// Pascal style strings
function Length(s:string):integer;
begin
    return  s[0];
end;

// UNICODE_STRING style strings
USHORT  ucs_len(PUNICODE_STRING pus)
{
    return	pus->Length;
}

  Проверка на пустоту

    Проверка - является ли строка пустой

ASCIIZ:
    Проверяем является ли первый символ строки нулевым символом

bool	is_string_null_or_empty(const char* s)
{
    if (!s) return true;
    return (*s == '\0');
}

Pascal:
    Проверяем равен ли нулю 0й символ строки

function is_empty_string(var s:string):boolean;
begin
    if s[0] = 0 then result := true;
    else result := false;
end;

UNICODE_STRING:
    Проверяем является ли длинна 0

BOOLEAN  IsUnicodeStringEmpty(PUNICODE_STRING ucs)
{
    return !ucs->Length;
}

  Емкость строки

    Вычисление сколько места может занимать строка
        capacity

ASCIIZ:
Pascal:
    никак - эта информация не храниться, программист должен
    сам это отслеживать.

UNICODE_STRING:

USHORT  UnicodeStringCapacity(PUNICODE_STRING ucs)
{
    return ucs->MaximumLength;
}

  Изменение емкости строки

    Выделение нового количества места под строку
        как правило растят только вверх
            прибавка зависит от длинны строки
                чем длиннее тем больше прибавляют
                    Например: для строк меньших 64 байт - 8 символов
                          для строк больших 64 байт - 32 символа

ASCIIZ:
Pascal:
    никак
UNICODE_STRING:
    можно выделить новый буфер, и туда все скопировать

  Индексация строки

Индексация для отдельных символов
    [index]
    Индексация символа в строке
        Выборка байта из строки по индексу
        Выборка символа из строки по индексу
            + выборка последнего символа

    [-index]
    Для индексации кроме того удобно использовать отрицательные индексы
    например -1 - это последний символ строки

Индексация для подстрок
    [startindex, length]
    [-startindex, length]

Разреженные подстроки
    [startindex, length, step]	[startindex, endindex, step]
    [startindex, length, -step]	[startindex, endindex, -step]

//Java

    public char charAt(int index);

  Выборка подстроки

    Выборка фиксированной подстроки
        левой	  	[0,length]
        правой	  	[-length, length]
        в середине      [position, length]
            multibyte version

// libpub

char* strright(const char* s, size_t n);	// возвращает указатель на
                        // n символов до конца строки
                        // в общем это right substring
                        // in place.

  Добавление к строке

    Добавление символа к строке
        в конец	  [-1]
        в начало  [0]
        в указанное место (вставка) [N]

    Добавление подстроки к строке
        в конец  [-1]
        в начало [0]
        в указанное место (вставка) [N]

Методы реализации очень разнообразные.

// libpub
void   strcins(char* s, int c);			// Insert character at start of string
char*  strins(char*  s, const char* substr);    // Insert string at start of string

// libpub
char*  strend(const char* s);			// возвращает указатель на нулевой символ
                        // в конце строки

char*  strend(const char* s)
{
    while(*s != '\0') s++;
    return	s;
}

char*  add_char_to_end_of_string(char * s, int c)
{
    char* p = strend(s);
    *p++ = c;
    *p = '\0';	// set trailing zero
    return	s;
}

Добавить строку в конец строки можно с помощью strcat().

  Объединение строк

    Объединение двух строк
    (Добавление строки к строке - естественно в конец [-1])

char*    strcat(char* dest, const char* src);
wchar_t* wcscat(wchar_t* dest, const wchar_t* src);

errno_t  strcat_s(char* dest, size_t noe, const char* src);

char*	 strncat(char* dest, const char* src, size_t count);
wchar_t* wcsncat(wchar_t* dest, const wchar_t* src, size_t count);

errno_t  strncat_s(char* dest, size_t noe, const char* src, size_t count);
errno_t  wcsncat_s(wchar_t* dest, size_t noe, const wchar_t* src, size_t count);

_tcscat
_tcsncat

char* strcat (char* dst, const char* src)
{
        char * cp = dst;

        while( *cp ) cp++;              // find end of dst
        while( *cp++ = *src++ ) ;       // Copy src to end of dst
        return( dst );                  // return dst
}

char * strncat(char * front, const char * back,  size_t count)
{
        char *start = front;

        while (*front++)  ;
        front--;

        while (count--)
    {
                if (!(*front++ = *back++))
        {
                        return(start);
        }
        }
        *front = '\0';;
        return(start);
}

// libpub
char*    stracat(const char* s, ...);
        // склеивает строки (последней в списке должен быть NULL)
        // возвращается указатель на аллокированный в куче блок
        // который содержит склеенные строки
        // или NULL если не получается выделить память

  Размножение строки

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

# Perl
    "X" x  5	# result is "XXXXX"

  Удаление из строки

    Удаление символа из строки
        [index,  1]
        [-index, 1]
            Особый случай - Trim  (описан ниже)
            в начале [0,  1]
            в конце  [-1, 1]
            и в начале и в конце

    Удаление подстроки
        [начало, длинна]
        [-начало, длинна]

    Удаление символов из строки
        список символов которые надо удалить
        Особый случай - обрезка whitespaces (описан ниже)
            в начале
            в конце
            и в начале и в конце

// Non-standard function
char* strdel(char *s, size_t offset, size_t count)
{
    size_t len = strlen(s);
    if (offset > len)
    {
            // if offset beyond end of string -- just do nothing
              return s;
    }
       if ((offset + count) > len)
    {
            count = size - offset;
    }
       strcpy(s + offset, s + offset + count);	   // имейте в виду:
                           // регионы перекрываются
    return s;
}

  Очистка строки

    Очистка строки

ASCIIZ:
    ставим 0 в первый байт строки
Pascal:
    ставим длинну в 0
UNICODE_STRING:
    ставим длинну в 0
    (если хотим можем еще и буфер удалить)

  Сравнение строк

    Сравнение двух строк
        сase-sensitive/case-insensitive
            strcmp
            strcmpi
        с учетом locale
            strcoll
            stricoll

int   strcmp(const char* s1,  const char* s2);
int   stricmp(const char* s1, const char* s2);
int   strcmpi(const char* s1, const char* s2);

int   strncmp(const char* s1, const char* s2, size_t count);
int   strnicmp(const char* s1, const char* s2, size_t count);

int   wcscmp(const wchar_t* s1, const wchar_t* s2);
int   wcsicmp(const wchar_t* s1, const wchar_t* s2);
int   wcsncmp(const wchar_t* s1, const wchar_t* s2, size_t count);
int   wcsnicmp(const wchar_t* s1, const wchar_t* s2, size_t count);

_tcscmp
_tcsicmp
_tcsncmp
_tcsnicmp

int __cdecl strcmp (const char * src, const char * dst)

{
        int ret = 0 ;

        while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
    {
                ++src, ++dst;
    }

        if ( ret < 0 )
    {
        ret = -1 ;
    } else if ( ret > 0 )
    {
                ret = 1 ;
    }
        return( ret );
}

int strcmpi(const char * dst, const char * src)
{
        int f,l;
        do
    {
                if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') )
        {
                    f -= ('A' - 'a');
        }

                if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') )
        {
                    l -= ('A' - 'a');
        }
        } while ( f && (f == l) );
        return(f - l);
}

int strncmp(const char* first, const char* last, size_t count)
{
        if (!count)
    {
                return(0);
    }

        while (--count && *first && *first == *last)
        {
                first++;
                last++;
        }

        return( *(unsigned char *)first - *(unsigned char *)last );
}

int strnicmp(const char * first, const char * last, size_t count)
{
        int f,l;
        if ( count )
        {
                do
        {
                        if ( ((f = (unsigned char)(*(first++))) >= 'A') && (f <= 'Z') )
                {
                f -= 'A' - 'a';
            }

                        if ( ((l = (unsigned char)(*(last++))) >= 'A') &&  (l <= 'Z') )
            {
                            l -= 'A' - 'a';
            }
                } while ( --count && f && (f == l) );

           return( f - l );
        }
        return( 0 );
}

C учетом locale:

Самые страшные сравнения - с учетом следования букв в алфавите.
Типовая оптимизация для сравнения - если длинна строк не равна то строки не равны.

Культурное сравнение хуже - строки могут быть равны если даже их длинны не равны:

Например пример из немецкого языка
Эти строки равны:

    Strasse
    StraBe

эсцет B - ss

int   strcoll(const char* s1, const char* s2);	  	// current locale
int   stricoll(const char* s1, const char* s2);
int   strncoll(const char* s1, const char* s2, size_t count);
int   strnicoll(const char* s1, const char* s2, size_t count);

int   wcscoll(const wchar_t* s1, const wchar_t* s2);    // current locale

_tcscoll
_tcsicoll
_tcsncoll
_tcsnicoll

//libpub
size_t  strdiff(const char *str1, const char *str2);	// возвращает позицию, где
                            // строки начали различаться

  Копирование строк

    Копирование строк

char* strcpy(char* dest, const char* src);
char* strncpy(char* dest, const char* src, size_t count);
        // count - количество символов которые должны быть скопированы

wchar_t* wcscpy(wchar_t* dest, const wchar_t* src);

errno_t strcpy_s(void* s1, size_t maxn, const void* s2);

_tcscpy
_tcscpy_s
_tcsncpy

char * strcpy(char * dst, const char * src)
{
        char * cp = dst;

        while( *cp++ = *src++ ) ;               // Copy src over dst
        return( dst );
}

char * strncpy(char* dest, const char* source, size_t count)
{
        char *start = dest;

        while (count && (*dest++ = *source++))    // copy string
    {
                count--;
    }

        if (count)                              // pad out with zeroes
    {
                while (--count)
                {
            *dest++ = '\0';
        }
    }
        return(start);
}

// libpub
char*  strmove(char* dest, char* src);	// strcpy для перекрывающихся областей

// libpub
int    stroverlap(const char* s1, const char* s2);  // проверяет перекрываются ли
                            // строки

  Создание копии строки

    Создание копии строки
        strdup

char*     strdup(const char* str);
wchar_t*  wcsdup(const wchar_t* str);
unsigned char*  mbsdup(const unsigned char* str);

_tcsdup

char * __cdecl strdup (const char * string)
{
        char *memory;

        if (!string)
    {
                return(NULL);
    }

        if (memory = malloc(strlen(string) + 1))
    {
                return(strcpy(memory,string));
    }

        return(NULL);
}

//libpub
char*     strndup(const char* str, size_t n);   // дуплицирует только первые n
                        // символов строки

  Заполнение строки шаблоном

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

char*  strset(char* str, int c);
char*  strnset(char* str, int c, size_t count);

wchar_t* wcsset(wchar_t* str, wchar_t c);
wchar_t* wcsnset(wchar_t* str, wchar_t c, size_t count);

errno_t  strset_s(char* str, size_t noe, int c);
errno_t  strnset_s(char* str, size_t noe, int c, size_t count);
errno_t  wcsset_s(wchar_t* str, size_t noe, wchar_t c);
errno_t  wcsnset_s(wchar_t* str, size_t noe, wchar_t c, size_t count);

    mbsset
    mbsnset
    mbsset_s
    mbsnset_s
    strset_l
    strnset_l
    strset_s_l
    strnset_s_l
    wcsset_l
    wcsnset_l
    wcsset_s_l
    wcsnset_s_l
    mbsset_s
    mbsnset_s
    mbsset_l
    mbsnset_l
    mbsset_s_l
    mbsnset_s_l

_tcsset
_tcsnset

char * strset (char * string, int val)
{
        char *start = string;

        while (*string)
    {
                *string++ = (char)val;
    }
        return(start);
}

char * strnset (char * string, int val, size_t count)
{
        char *start = string;

        while (count-- && *string)
    {
                *string++ = (char)val;
        }
        return(start);
}

  Поиск символа или группы символов

    поиск символа
        первого вхождения
        последнего вхождения
            case-sensitive
            case-nonsensitive
    поиск группы символов
        с начала
        с конца
            (case не нужен, потому что можно и upper и lower поместить
             прямо в группу символов).

Поиск конкретного символа:

char*  strchr(const char* s, int c);		// C
char*  strchr(char* s, int c);			// C++
const char* strchr(const char* s, int c);       // C++

char*  strrchr(const char* s, int c);		// C
char*  strrchr(char* s, int c);			// C++
const char* strrchr(const char* s, int c);	// C++

wchar_t* wcschr(const wchar_t* s, wchar_t c);	// C
                        // еще есть 2 C++
wchar_t* wcsrchr(const wchar_t* s, wchar_t c);  // C
                        // еще есть 2 C++

_tcschr
_tcsrchr

char * strchr(const char * string, int ch)
{
        while (*string && *string != (char)ch)
    {
        string++;
    }
        if (*string == (char)ch)
    {
                return((char *)string);
    }
        return(NULL);
}

char * strrchr(const char * string, int ch)
{
        char *start = (char *)string;

        while (*string++) ;                     /* find end of string */
                                                /* search towards front */
        while (--string != start && *string != (char)ch) ;

        if (*string == (char)ch)                /* char found ? */
    {
                return( (char *)string );
        }
        return(NULL);
}

В некоторых имплементациях (в первую очередь для микроконтроллеров есть нестандартные
варианты, которые обеспечивают case-insensitive поиск:

char*  strichr(const char* string, int ch);
char*  strrichr(const char* string, int ch);

Поиск символа входящего или не входящего в группу символов:

size_t  strspn(const char* s, const char* charset);      // Not belong: Index
char*   strspnp(const char* s, const char* charset);	 // Not belong: Pointer
size_t  strcspn(const char* s, const char* charset);	 // Belong:  Index
char*   strpbrk(const char* s, const char* charset);	 // Belong:  pointer

_tcsspn
_tcsspbp
_tcspbrk

size_t strspn(const char * string, const char * control)
{
        const unsigned char *str = string;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

        /* Clear out bit map */
        for (count=0; count<32; count++)
                map[count] = 0;

        /* Set bits in control map */
        while (*ctrl)
        {
                map[*ctrl >> 3] |= (1 << (*ctrl & 7));
                ctrl++;
        }

        /* 1st char NOT in control map stops search */
        if (*str)
        {
                count=0;
                while (map[*str >> 3] & (1 << (*str & 7)))
                {
                        count++;
                        str++;
                }
                return(count);
        }
        return(0);
}

size_t __cdecl strcspn (const char * string, const char * control)
{
        const unsigned char *str = string;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

        /* Clear out bit map */
        for (count=0; count<32; count++)
                map[count] = 0;

        /* Set bits in control map */
        while (*ctrl)
        {
                map[*ctrl >> 3] |= (1 << (*ctrl & 7));
                ctrl++;
        }

        /* 1st char in control map stops search */
        count=0;
        map[0] |= 1;    /* null chars not considered */
        while (!(map[*str >> 3] & (1 << (*str & 7))))
        {
                count++;
                str++;
        }
        return(count);
}

char * strpbrk(const char * string, const char * control)

{
        const unsigned char *str = string;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

        /* Clear out bit map */
        for (count=0; count<32; count++)
                map[count] = 0;

        /* Set bits in control map */
        while (*ctrl)
        {
                map[*ctrl >> 3] |= (1 << (*ctrl & 7));
                ctrl++;
        }

        /* 1st char in control map stops search */
        while (*str)
        {
                if (map[*str >> 3] & (1 << (*str & 7)))
                        return((char *)str);
                str++;
        }
        return(NULL);
}

size_t   wcsspn(const wchar_t* s, const wchar_t* charset);
wchar_t* wcsspnp(const wchar_t* s, const wchar_t* charset);
size_t   wcscspn(const wchar_t* s, const wchar_t* charset);
wchar_t* wcspbrk(const wchar_t* s, const wchar_t* charset);

  Поиск подстроки

    Поиск фиксированной подстроки в строке
        начиная с указанного места
        начиная с Nго совпадения
        начиная с конца
            case-sensitive
            case-insensitive

    Поиск несовпадающей подстроки
        *

char*  strstr(const char* s, const char* substr);  	// C
char*  strstr(char* s, const char* substr);	   	// C++
const char* strstr(const char* s, const char* substr);  // C++

wchar_t* wcsstr(const wchar_t* s, const wchar_t* substr); // C
                              // еще есть 2 C++

_tcsstr

char * strstr (const char * str1, const char * str2)
{
        char *cp = (char *) str1;
        char *s1, *s2;

        if ( !*str2 )
    {
            return((char *)str1);
    }

        while (*cp)
        {
                s1 = cp;
                s2 = (char *) str2;

                while ( *s1 && *s2 && !(*s1-*s2) )
        {
                        s1++, s2++;
                }

                if (!*s2)
        {
                        return(cp);
        }
                cp++;
        }
        return(NULL);
}

//libpub

char* strrstr(const char* s, const char* substr);   // поиск подстроки с конца

// PIC
char* stristr(const char* s, const char* substr);   // case-insensitive вариант

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

char*  strtok(char* stok, const char* delim);

char*  strtok_s(char* stok, const char* delim, char** context);

wchar_t* wcstok(wchar_t* stok, const wchar_t* delim);

_tcstok

char * strtok (char * string, const char * control)
{
        unsigned char *str;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

        static char *nextoken;

        /* Clear control map */
        for (count = 0; count < 32; count++)
    {
                map[count] = 0;
        }

        /* Set bits in delimiter table */
        do
    {
                map[*ctrl >> 3] |= (1 << (*ctrl & 7));
        } while (*ctrl++);

        /* Initialize str. If string is NULL, set str to the saved
         * pointer (i.e., continue breaking tokens out of the string
         * from the last strtok call) */
        if (string)
    {
                str = string;
    } else {
                str = nextoken;
    }

        /* Find beginning of token (skip over leading delimiters). Note that
         * there is no token iff this loop sets str to point to the terminal
         * null (*str == '\0') */
        while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
    {
                str++;
        }

        string = str;

        /* Find the end of the token. If it is not the end of the string,
         * put a null there. */
        for ( ; *str ; str++ )
    {
                if ( map[*str >> 3] & (1 << (*str & 7)) )
        {
                        *str++ = '\0';
                        break;
                }
    }

        /* Update nextoken (or the corresponding field in the per-thread data
         * structure */
        nextoken = str;

        /* Determine if a token has been found. */
        if ( string == str )
    {
                return NULL;
        } else {
                return string;
    }
}

// использование strtok:

char seps[]   = " ,\t\n";
char *token;

int main( void )
{
    printf( "Tokens:\n" );

    // Establish string and get the first token:
    token = strtok( string, seps );

    while( token != NULL )
    {
              // While there are tokens in "string"
              printf( " %s\n", token );

              // Get next token:
              token = strtok( NULL, seps );
    }
}

Проблема strtok, то что указатель на следущей токен лежит
в глобальной переменной - поэтому проблемы у многопоточных
апликаций (при отсутвии TLS).
Для этого есть Thread safe вариант:

// POSIX
char *strtok_r(char *restrict s, const char *restrict sep,
                  char **restrict lasts);

  Замена

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

C#
    string Replace(char ch1, char ch2)
    string Replace(string s1, string s2)

// libpub
char* strsub(char* s, const char* pattern, const char* substr);
            // выполняет замену для первого с начала строки
            // вхождения паттерна

int   strgsub(char* s, const char* pattern, const char* substr, size_t max);
            // выполняет глобальную (т.е. все вхождения) замену подстрок

tr//

Python
    tbl = s.maketrans(str_source_chars, str_result_chars);
    s2.translate(tbl);

  Удаление заданной группы символов

Ruby
    s.delete("b") 		// удаляет все символы b в строке
    s.delete("cd")		// удаляет все символы c и d в строке

  Подсчет числа вхождений в строку символов из данного набора

Ruby
    s1.count("s")		// вхожящих в набор
    s1.count("^bcd")	// невходящих в набор
    s1.count("a-d")		// входящих в набор
    s1.count("^a-dz")	// невходящих в набор

  Подсчет числа вхождений в строку подстроки

Python
    s.count(substr)
    s.count(substr, start)
    s.count(substr, start, end)

  Разбиение строки на части подстрокой

В результате получается 3 строки:
    before_substring	или вся строка если non-match
    substring		или пустая строка если non-match
    after_substring		или пустая строка если non-match

Python

    s.partition(substr)	// ищет подстроку слева
    s.rpartition(substr)	// ищет подстроку справа

  Капитализация и декапитализация

    Upcase
    Locase
    Swapcase
        для всей строки
        для первого символа строки

    Дополнительно для Unicode
        есть третий case - title case

char*	  strlwr(char* str);
char*	  strupr(char* str);

wchar_t*  wcslwr(wchar_t* str);
wchar_t*  wcsupr(wchar_t* str);

errno_t	  strlwr_s(char* str, size_t noe);
errno_t   strupr_s(char* str, size_t noe);
errno_t	  wcslwr_s(wchar_t* str, size_t noe);
errno_t   wcsupr_s(wchar_t* str, size_t noe);

_tcslwr
_tcsupr

// C locale имплементация

char * strlwr (char * string)
{
        char *cp;               	// traverses string for C locale conversion
        for (cp=string; *cp; ++cp)
        {
            if ('A' <= *cp && *cp <= 'Z')
                    *cp += 'a' - 'A';
        }
        return(string);
}

char * strupr(char * string)
{
        char *cp;       		// traverses string for C locale conversion
        for (cp = string; *cp; ++cp)
        {
            if ('a' <= *cp && *cp <= 'z')
                *cp += 'A' - 'a';
        }
        return(string);
}

    mbsupr
    mbsupr_s
char*	strupr_l(char* str, locale_t locale);
    wcsupr_l
    mbsupr_l

// Ruby
    s.swapcase	// меняят регистр каждой буквы на противоположный

Капитализация и декапитализация сложный процесс.
Он зависит от используемой кодировки.

// multiple-locale имплементация

char*  strupr_l(char* str, locale_t locale)
{
    char* cp;
    for (cp = str; *cp; cp++)
    {
        *cp = __upcase_for_locale(locale, *cp);
    }
    return	str;
}

char*  strupr(char* str)
{
    char* cp;
    for (cp = str; *cp; cp++)
    {
        *cp = __upcase_for_locale(__current_locale, *cp);
    }
    return	str;
}

Реально держат таблицы для upcase и locase для соответсвующей кодовой страницы.
(плюс естествнно таблицы для Unicode (нужны для Unicode: и UTF-8 и UTF-16,
но они из-за размеров на самом деле получаются смесью страниц и аналитических выражений).

// Пример таблиц для Lowcase и Upcase для кодировки ANSI1251 (Russian Cyrillic)

static unsigned char charset2lower[256] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
    0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
    0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
    0x90, 0x83, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
    0x88, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
    0xa0, 0xa2, 0xa2, 0xbc, 0xa4, 0xb4, 0xa6, 0xa7, /* 0xa0-0xa7 */
    0xb8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */
    0xb0, 0xb1, 0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
};

static unsigned char charset2upper[256] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
    0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
    0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
    0x80, 0x81, 0x82, 0x81, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
    0x80, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
    0x98, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */
    0xa0, 0xa1, 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
    0xb0, 0xb1, 0xb2, 0xb2, 0xa5, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
    0xa8, 0xb9, 0xaa, 0xbb, 0xa3, 0xbd, 0xbd, 0xaf, /* 0xb8-0xbf */
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */
};

  Перевертывание строки

char*   strrev(char* str);

wchar_t* wcsrev(wchar_t* str);

_tcsrev

char*  strrev(char* str)
{
    size_t len = strlen(str);
    return memrev(str, 1, len);
}

  Обрезка строки

    Удаление первого и последнего символа (Trim)
        только первого
        только последнего
        и первого и последнего

//C#
    string	Trim();
    string	Trim(char[]);
    string	TrimStart();
    string	TrimStart(char[]);
    string	TrimEnd();
    string	TrimEnd(char[]);

// libpub
int	strzap(char* s, const char* pattern);	// если в начале строки находиться
                        // pattern, то его удаляют
int	strnzap(char* s, const char* pattern);  // если в конце строки нахожиться
                        // pattern, то его удаляют
// возвращают 0, если ничего не удалили

  Обрезка Whitespaces

    Частный случай удаления указанного набора символов
        в начале
        в конце
        и в начале и в конце

Собственно whitespaces это:
        \n
        \r
        \t
        \v
        \0
        ' '

// libpub

char*  strltrim(char* s);	// Remove leading whitespaces
char*  strrtrim(char* s);	// Remove trailing whitespaces
char*  strtrim(char* s);	// Removing leading and trailing whitespaces

char*  strtrim(char* s)
{
    return	strltrim(strrtrim(s));
}

// libpub
char*  strmtrim(char* s);	// заменяет все whitespaces run внутри строки
                // на единичные whitespaces (то есть содержащие
                // всего один символ - пробел).

  Удаление дубликатов символов

Ruby

    s.squeeze(".")		// везде где были группы точек остается только одна
                // кстати ^ и - внутри тоже можно использовать

  Замена табуляций на пробелы и обратно.

    TAB (09h)
    обычное значение 8 или 4.

// libpub
char*  strtabify(char* s, size_t tabsize);
char*  struntabify(char* s, size_t tabsize);

  Дополнение строки до нужного размера

C#
    string	PadLeft(int length)
    string	PadLeft(int length, char pad)
    string	PadRight(int length)
    string	PadRight(int length, char pad)

Python

    s.center(width,char)		// строка в центре
    s.ljust(width, char)
    s.rjust(width, char)

  Получение hash кода

    Удобно иметь стандартную функцию для hash кода для сток (Java)

//libpub

unsigned long strhash(const char* s);	// вычисляет hash строки

  Rot13

Rotate 13 (всего в английском языке 26 букв).
Это популярный в USENETе метод для скрытия текста.
(кроме того RTL для поддержки есть в многих языках - например в Ruby).

    a -> n		A -> N
    b -> o		B -> O
    ...		...
    m -> z		M -> Z
    n -> a		N -> A
    ...		...
    z -> m		Z -> M

    A B C D E F G H I J K L M
    N O P Q R S T U V W X Y Z

// libpub

char*  strrot13(char* str);

  Перевод строк C типа в бинарные и обратно

Зачем это надо: поскольку компилятор предобрабатывет строки - иногда надо
это делать самим (например строка во внешнем файле) или делать в другую
сторону.

    '	- >	\'
    "	- >	\"
    \	- >	\\
    \0	- >	\0
    \n
    \r
    \t
    \v
    \b

  Конвертация недопустимых символов в НTML

Существует набор символов которые не могут находиться непосредственно
в текстах внутри HTML. В связи с распространением Internet такая операция
очень популярна в современных яыках.

    &	->	&amp;
    "	->	&quot;
    <	->	&lt;
    >	->	&gt;

  Дистанция Левенштейна

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

Элементарные модификации это:

    имя  стоимость  описание
    ins	1	вставка символа
    del     1	удаление символа
    rep     2	замена символа

Дистанция Левенштейна используется для:
    Проверка орфографии
        Исправление ошибок при вводе текста
    Поиск с неполно-заданным или неточно-заданным именем
    В поисковых системах для нахождения объектов по именам

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

                     |  0		if  i = 0, j = 0
d(S1,S2) = D(n,m) =  |  i		if  i > 0, j = 0
             |  j		if  i = 0, j > 0
             |  min(D(i, j-1) + 1,
             |      D(i-1, j) + 1,
             |	    D(i-1, j-1) + m(S1[i], S2[j])	if i >0, j > 0

    где

       m(a, b) = |  0	if a == b
             |  1	if a != b

Шаг по i - это удаление из 1й строки
Шаг по j - это вставка  в  1ю строку
Шаг по обеим индексам - либо замену (Replacement), либо отсутсвие изменений

  Конвертация строк

  Конвертация в строку другого типа

    Конвертация строки в другую строку
        другово типа
        другово locale
        и то и другое вместе

Конвертация в строку другого типа:

{ Delphi }

function StrPas(s:PChar): string;		{ ASCIIZ to Pascal }
function StrPCopy(str:Pchar; s:string) : Pchar; { Pascal to Asciiz }

Конвертация в строку того же типа но другого Locale.

Конвертация в строку другой разрядности

Основа конвертации в строку другого locale:

В настоящее время как правило конвертация происходит через
UNICODE.

One_Locale => Unicode => Another_Locale

Два способа:
    Табличный
    Аналитический

Как правило есть таблицы для конвертации codepage в Unicode.
Для single byte - они простые - занимают 512 байт, и содержат
Unicode character для каждого символа.

// Пример таблицы для перекодировки CP866 в UNICODE

static word charset2uni[256] = {
    /* 0x00*/
    0x0000, 0x0001, 0x0002, 0x0003,
    0x0004, 0x0005, 0x0006, 0x0007,
    0x0008, 0x0009, 0x000a, 0x000b,
    0x000c, 0x000d, 0x000e, 0x000f,
    /* 0x10*/
    0x0010, 0x0011, 0x0012, 0x0013,
    0x0014, 0x0015, 0x0016, 0x0017,
    0x0018, 0x0019, 0x001a, 0x001b,
    0x001c, 0x001d, 0x001e, 0x001f,
    /* 0x20*/
    0x0020, 0x0021, 0x0022, 0x0023,
    0x0024, 0x0025, 0x0026, 0x0027,
    0x0028, 0x0029, 0x002a, 0x002b,
    0x002c, 0x002d, 0x002e, 0x002f,
    /* 0x30*/
    0x0030, 0x0031, 0x0032, 0x0033,
    0x0034, 0x0035, 0x0036, 0x0037,
    0x0038, 0x0039, 0x003a, 0x003b,
    0x003c, 0x003d, 0x003e, 0x003f,
    /* 0x40*/
    0x0040, 0x0041, 0x0042, 0x0043,
    0x0044, 0x0045, 0x0046, 0x0047,
    0x0048, 0x0049, 0x004a, 0x004b,
    0x004c, 0x004d, 0x004e, 0x004f,
    /* 0x50*/
    0x0050, 0x0051, 0x0052, 0x0053,
    0x0054, 0x0055, 0x0056, 0x0057,
    0x0058, 0x0059, 0x005a, 0x005b,
    0x005c, 0x005d, 0x005e, 0x005f,
    /* 0x60*/
    0x0060, 0x0061, 0x0062, 0x0063,
    0x0064, 0x0065, 0x0066, 0x0067,
    0x0068, 0x0069, 0x006a, 0x006b,
    0x006c, 0x006d, 0x006e, 0x006f,
    /* 0x70*/
    0x0070, 0x0071, 0x0072, 0x0073,
    0x0074, 0x0075, 0x0076, 0x0077,
    0x0078, 0x0079, 0x007a, 0x007b,
    0x007c, 0x007d, 0x007e, 0x007f,
    /* 0x80*/
    0x0410, 0x0411, 0x0412, 0x0413,
    0x0414, 0x0415, 0x0416, 0x0417,
    0x0418, 0x0419, 0x041a, 0x041b,
    0x041c, 0x041d, 0x041e, 0x041f,
    /* 0x90*/
    0x0420, 0x0421, 0x0422, 0x0423,
    0x0424, 0x0425, 0x0426, 0x0427,
    0x0428, 0x0429, 0x042a, 0x042b,
    0x042c, 0x042d, 0x042e, 0x042f,
    /* 0xa0*/
    0x0430, 0x0431, 0x0432, 0x0433,
    0x0434, 0x0435, 0x0436, 0x0437,
    0x0438, 0x0439, 0x043a, 0x043b,
    0x043c, 0x043d, 0x043e, 0x043f,
    /* 0xb0*/
    0x2591, 0x2592, 0x2593, 0x2502,
    0x2524, 0x2561, 0x2562, 0x2556,
    0x2555, 0x2563, 0x2551, 0x2557,
    0x255d, 0x255c, 0x255b, 0x2510,
    /* 0xc0*/
    0x2514, 0x2534, 0x252c, 0x251c,
    0x2500, 0x253c, 0x255e, 0x255f,
    0x255a, 0x2554, 0x2569, 0x2566,
    0x2560, 0x2550, 0x256c, 0x2567,
    /* 0xd0*/
    0x2568, 0x2564, 0x2565, 0x2559,
    0x2558, 0x2552, 0x2553, 0x256b,
    0x256a, 0x2518, 0x250c, 0x2588,
    0x2584, 0x258c, 0x2590, 0x2580,
    /* 0xe0*/
    0x0440, 0x0441, 0x0442, 0x0443,
    0x0444, 0x0445, 0x0446, 0x0447,
    0x0448, 0x0449, 0x044a, 0x044b,
    0x044c, 0x044d, 0x044e, 0x044f,
    /* 0xf0*/
    0x0401, 0x0451, 0x0404, 0x0454,
    0x0407, 0x0457, 0x040e, 0x045e,
    0x00b0, 0x2219, 0x00b7, 0x221a,
    0x2116, 0x00a4, 0x25a0, 0x00a0,
};

Аналитический способ подразумевает функцию которая вполняет
теже действия.

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

Первая ступень - показывает какие страницы фиксированного размера
(как правило 128 или 256 символов) используются target кодировкой.
Если страница используется то кладеться указатель на страницу.
Если не используется то кладеться NULL.

А уже страница содержит байтовые коды символов в указанной кодировке.
Если символ не представим, то пишиться 0 например, и тогда преобразователь
будет знать.

Операционные системы как правило содержат API которыми можно пользоваться:

 Windows

int MultiByteToWideChar(
      UINT CodePage,  		// CP_ACP - current ANSI, CP_OEMCP, CP_UTF8
      DWORD dwFlags,
      LPCSTR lpMultiByteStr, 	// source
      int cbMultiByte,       	// source length (in bytes)
      LPWSTR lpWideCharStr,  	// destination
      int cchWideChar);		// destination length (in wide chars)
                    // if = 0 return required buffer size

int WideCharToMultiByte(
      UINT CodePage,
      DWORD dwFlags,
      LPCWSTR lpWideCharStr,
      int cchWideChar,
      LPSTR lpMultiByteStr,
      int cbMultiByte,
      LPCSTR lpDefaultChar,    	// Pointer to character used if unicode char
                    // can not be represented in code page
      LPBOOL lpUsedDefaultChar);	// Set to TRUE if at least one char was presented
                    // as default.

Конвертация в строку другого locale:

Python
    s.encode("Latin1")
    s.encode("CP850")
    s.encode("utf8")
    s.encode("utf16")
    s.encode("US_ASCII")

  Нормализация строки

Имеет смысл для Unicode строк (и UTF-8).
Смысл: сведение к соответсвующей нормальной форме Unicode.

  Смена Endian для строки

Имеет смысл только для Wide (16-бит) и Ultra-Wide (32-бит) типов строк.

Endian в строках.

Как правило идет как один из вариантов конвертации строки

  Некоторые примитивы для работы с Multibyte

unsigned char*  mbsdec(const unsigned char* start,	// move back one character
               const unsigned char* current);

unsigned char*  mbsinc(const unsigned char* current);	// move forward one character

unsigned char*  mbsninc(const unsigned char* str,	// advance by count characters
            size_t count);

size_t		mbsnbcnt(const unsigned char* str,	// return number of bytes
             size_t count);			// for first count characters

size_t		strncnt(const char* str, size_t count);	    // return number of characters
                                // in first count bytes
size_t		wcsncnt(const wchar_t* str, size_t count);  // return number of wide-characters
                                // in first count wide-characters

_tcsinc
_tcsdec
_tcsninc
_tcsnextc

  TCHAR

typedef char CHAR;
typedef wchar_t WCHAR;

typedef CHAR* PCHAR;
typedef CHAR* PSTR;
typedef CONST CHAR * PCSTR;

typedef WCHAR* PWCHAR;
typedef WCHAR* PWSTR;
typedef CONST WCHAR* PCWSTR;

#ifdef UNICODE
typedef WCHAR TCHAR, *PTCHAR , PTSTR;
typedef CONST WCHAR * PCTSTR;
#define	__TEXT(quote) L##quote
#else
typedef CHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST CHAR* PCTSTR;
#define __TEXT(quote) quote
#endif

#define TEXT(quote) __TEXT(quote)

#ifdef UNICODE
#define	CreateFile	CreateFileW
#else
#define	CreateFile	CreateFileA
#endif

#ifdef	UNICODE
#define	_tcslen		wcslen
#else
#define	_tcslen		strlen
#endif


70.2.6.1.0. ПРОКЛАДКИ ДЛЯ КОНВЕРТАЦИИ СТРОК

THIS SECTION IS UNDER CONSTRUCTION

На примере ATL прокладок

template< int t_nBufferLength = 128 >
class CA2WEX
{
public:
    CA2WEX( _In_opt_ LPCSTR psz ) throw(...) :
        m_psz( m_szBuffer )
    {
        Init( psz, _AtlGetConversionACP() );
    }
    CA2WEX( _In_opt_ LPCSTR psz, UINT nCodePage ) throw(...) :
        m_psz( m_szBuffer )
    {
        Init( psz, nCodePage );
    }
    ~CA2WEX() throw()
    {
        AtlConvFreeMemory(m_psz,m_szBuffer,t_nBufferLength);
    }

    operator LPWSTR() const throw()
    {
        return( m_psz );
    }

private:
    void Init( _In_opt_ LPCSTR psz, UINT nCodePage ) throw(...)
    {
        if (psz == NULL)
        {
            m_psz = NULL;
            return;
        }
        int nLengthA = lstrlenA( psz )+1;
        int nLengthW = nLengthA;

        AtlConvAllocMemory(&m_psz,nLengthW,m_szBuffer,t_nBufferLength);

        BOOL bFailed=(0 == ::MultiByteToWideChar( nCodePage, 0, psz, nLengthA, m_psz, nLengthW ) );
        if (bFailed)
        {
            if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
            {
                nLengthW = ::MultiByteToWideChar( nCodePage, 0, psz, nLengthA, NULL, 0);
                AtlConvAllocMemory(&m_psz,nLengthW,m_szBuffer,t_nBufferLength);
                bFailed=(0 == ::MultiByteToWideChar( nCodePage, 0, psz, nLengthA, m_psz, nLengthW ) );
            }
        }
        if (bFailed)
        {
            AtlThrowLastWin32();
        }
    }

public:
    LPWSTR m_psz;
    wchar_t m_szBuffer[t_nBufferLength];

private:
    CA2WEX( const CA2WEX& ) throw();
    CA2WEX& operator=( const CA2WEX& ) throw();
};
typedef CA2WEX<> CA2W;


70.2.6.1.1. АЛГОРИТМЫ НА СТРОКАХ

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

Собственно алгоритмы можно разбить на 3 группы:
    1) Тупой
           [двойной цикл]
    2) Нечеткое сравнение сразу всего шаблона
       [уменьшение числа выполнений внутреннего цикла]
    3) Умный сдвиг окна во время поиска в случае несовпадения
       [уменьшение числа выполнений внешнего цикла]

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

    -------------------------------------------------------------
                    худшее  среднее	  затраты
                    время   время     памяти
    -------------------------------------------------------------
    Тупой алгоритм			O(n*m)   2*n       0
    -------------------------------------------------------------
    Алгоритм Рабина-Карпа		O(n*m)	 O(n+m)    0
    -------------------------------------------------------------
    Алгоритм Бойерса-Мура		O(m*n)   O(n+m)    O(m+s)
    Алгоритм Кнута-Морриса-Прата	O(n+m)   O(n+m)    O(m)
    -------------------------------------------------------------

  Тупой алгоритм

Просто идем по строке слева направо и пытаемся сравнивать каждый раз с шаблоном.
(Понятно что если длинна строки n, а длинна шаблона m - то имеет смысл сравнивать
только подстроки лежащие в диапазоне [0..n-m] строки в которой осуществляется поиск.

Если шаблон не совпал - сдвигаемся на 1 символ вправо и повторяем.

Если шаблон совпал - то мы нашли то что хотели
Если несовпал ни разу - значит нет такой подстроки в строке.

char*   strstr(const char* s, const char* sub)
{
    return memmem(s, strlen(s), sub, strlen(sub));
}

void*	memmem(const char* s, int n, const char* sub, int m)
{
    for (int i = 0; i <= (n - m); i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (s[i+j] != sub[j]) goto not_found;
        }
        return &s[i];
not_found:
        ;
    }
    return	NULL;
}

  Алгоритм Рабина-Карпа

Смысл алгоритма: Ускорение проверки используя hash-функцию
Если строки одинаковые то их hash тоже одинаковый.
Соответсвенно внутренний цикл тупого алгоритма выполняют только для случая
если hash совпадает.

Вначале вычисляется hash функция для подстроки
Это одноразовая операция

Затем считают hash начала строки.
Сравнивают - если несовпал то смещаются на 1 символ, обновляют hash,
и делают все снова.

Если hash совпал, то сравнивают саму подстроку.
Если не совпала, то смещаемся на 1 символ, обновляем hash и все снова.

Если hash и подстрока совпали - то match.

bool	rabin_karp_search_substr(const char* s, const char* sub)
{
    int n = strlen(s);
    int m = strlen(sub);

    hash_t hsub = hash(sub, m); 	// (ptr, length)
    hash_t hs   = hash(s,   m);

    for (int i = 0; i <= (n-m); i++)
    {
        if (hs == hsum)
        {
            // если hash совпал, то смотрим на точное совпадение
            if (memcmp(&s[i], sub, m) == 0) return i;
        }
        hs = memhashupdate(hs, s[i], s[i+m]);	// реально пересчет по символам
                            // то есть один сверху отнимают
                            // второй добавляют снизу
    }
    return	NOT_FOUND;
}

Кольцевая hash функция:

простой пример (который был использован в иллюстрациях):

typedef char hash_t;

hash_t  hash(char* s, int length)
{
    char result = 0;
    for (int i = 0; i < length; i++) result += s[i];
    return	result;
}

hash_t	memhashupdate(hash_t old, char removech, char addch)
{
    return	old - removech + addch;
}

Наиболее эффективные hash функции - которые представляют hash значение как число в
системе с каким нибудь простым основанием.

Алгоритм Рабина-Карпа хорош еще тем, что в отличии от остальных алгоритмов его
можно использовать и для паралельного поиска нескольких подстрок.

Но к сожалению подходит только для case-sensitive поиска подстрок.

  Алгоритм Бойерса-Мура-Хорспула

Это упрощенный вариант алгоритма Бойерса-Мура (о котором будет написано ниже).
(Используется только stop-символ, суффиксы для подстрок не используются).

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

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

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

Например:

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

Основная фаза:

Поиск осуществляется с начала текста: шаблон совмещается с началом текста.

Смотриться совпадения последнего символа шаблона с соответсвующим символом
строки.
Если совпадения нет, то смотрится таблица символов (по индексу символа СТРОКИ).
Если такого символа в таблице нет (это означает что символа нет в шаблоне),
то мы сразу сдвигаем наш поиск вправо на длинну шаблона.

Если же есть совпадение с последним символом, но какой то из более ранних
не совпадает, то продвигаемся на 1 символ.

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

Если же есть совпадение с последним символом и со всеми предидущими - то
мы нашли match.

Если мы дошли до конца строки  и там тоже обломались (или сдвиг нас выводит за конец строки)
значит нет такой подстроки в строке.

procedure boyer_moore(const haystack: string; const needle: string; var result: byte);
var
        i, j, k      : byte;
        needle_len   : byte;
        haystack_len : byte;
        needle_table : array[char] of byte;
begin

    needle_len := length(needle);
    haystack_len := length(haystack);

    if needle_len < haystack_len then
    begin
            for i := 0 to 255 do
                    needle_table[chr(i)] := needle_len;
            for i := 1 to needle_len-1 do
                    needle_table[needle[i]] := needle_len-i;

            i := needle_len;
            j := i;
            while (j > 0) and (i <= haystack_len) do
            begin
                    j := needle_len; k := i;
                    while (j > 0) and (haystack[k] = needle[j]) do
                    begin
                            dec(k);
                            dec(j);
                    end;
                    i := i + needle_table[haystack[i]];
            end;
        if k > haystack_len - needle_len then
        begin
                    result := 0
            end else begin
                    result := k + 1;
        end;
    end else begin
            result := 0;
    end;
end;

Алгоритм Бойерса-Мура-Хорспула можно адаптировать к case insensitive поиску.

Недостатки: Сложности на больших алфавитах (Unicode). Тогда либо данные хранят
в Hash-таблицах, либо дробят алфавит на байты.

  Алгоритм Бойерса-Мура

Дополнительные возможности по сравнению с Алгоритмом Бойерса-Мура-Хорспула, в том
что кроме stop-символа еще используются таблица суффиксов, для того что если суффикс
совпал (то есть совпадений больше чем stop-символ), то сразу передвинуться не на 1
символ, а на большее количество.

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

Пример таблицы суффиксов для шаблона "BADBAD":

Пример таблицы суффиксов для шаблона "BADSAD":

К сожалению - построение таблицы суффиксов - это дополнительная работа.
И вопрос работает ли алгоритм Бойерса-Мура быстрее чем алгоритм Бойерса-Мура-Хорспула
зависит от характера данных.

#include <string.h>
#include <limits.h>

/* Вход: needle+nlen - что искать
 *   offset - позиция конца суффикса; suffixlen - его длина
 * Выход: 1, если есть совпадение суффикса (и нет совпадения более длинного суффикса)
 */
static int suffix_match(const unsigned char *needle, size_t nlen, size_t offset, size_t suffixlen)
{
    if (offset > suffixlen)
    {
            return needle[offset - suffixlen - 1] != needle[nlen - suffixlen - 1] &&
                    memcmp(needle + nlen - suffixlen, needle + offset - suffixlen, suffixlen) == 0;
    } else {
            return memcmp(needle + nlen - offset, needle, offset) == 0;
    }
}

static ssize_t max(ssize_t a, ssize_t b)
{
        return a > b ? a : b;
}

/* Вход: haystack - где искать, needle - что искать.
 *   hlen - длина haystack, nlen - длина needle
 * Выход: указатель на первое вхождение needle в haystack, либо NULL
 */
const unsigned char* memmem_boyermoore
    (const unsigned char* haystack, size_t hlen,
     const unsigned char* needle,   size_t nlen)
{
        size_t skip[nlen];          /* Таблица суффиксов */
        ssize_t occ[UCHAR_MAX + 1]; /* Таблица стоп-символов */

        if(nlen > hlen || nlen <= 0 || !haystack || !needle)
    {
            return NULL;
        }

        /* ПОСТРОЕНИЕ ТАБЛИЦЫ СТОП-СИМВОЛОВ */

        /* Заполняем -1 (в Си нумерация символов с 0!!) */
        for(size_t a=0; a<UCHAR_MAX+1; ++a)
    {
        occ[a] = -1;
    }

        /* В таблицу occ записывается последнее вхождение в needle  */
        /* (исключая последний символ) */
        for(size_t a = 0; a < nlen - 1; ++a)
    {
            occ[needle[a]] = a;
    }

        /* ПОСТРОЕНИЕ ТАБЛИЦЫ СУФФИКСОВ */
        /* Упрощённый вариант. Можно реализовать быстрее. */
        for(size_t a = 0; a < nlen; ++a)
        {
                size_t offs = nlen;
                while(offs && !suffix_match(needle, nlen, offs, a))
            {
                  --offs;
        }
            skip[nlen - a - 1] = nlen - offs;
        }

        /* ПОИСК */
        for(size_t hpos = 0; hpos <= hlen - nlen; )
        {
            size_t npos = nlen - 1;
            /* Сверка needle и haystack с конца */
            while(needle[npos] == haystack[npos + hpos])
            {
                    if (npos == 0)
            {
                        return haystack + hpos;
                        }
                    --npos;
            }

            /* Не совпало! */
            hpos += max(skip[npos], npos - occ[haystack[npos + hpos]]);
            /*          ^^^         ^^^^                               */
            /*        суффикс     стоп-символ                          */
        }
        return NULL;
}

  Алгоритм Кнута-Морриса-Пратта

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

Длинна наиболее длинного префикса в шаблоне являющегося суффиксом - префикс-функция
от шаблона.
p[j] = префикс функция от PATTERN[0, j-1]

Стадия предобработки:

Стадия сравнения:

Пусть мы сравнивали текст на i позиции.
Несовподение возникло на j позиции шаблона.
Мы можем возобнавить сравнение  с места в тексте i+j, и места в шаблоне p[j]
без потери возможного местонахождениея совпадения.

int  seek_substring_KMP  (char* s, char *q)
{
    int  i, j, N, M;

    N = strlen(s);

    M = strlen(q);

    int *d =(int*)malloc(M*sizeof(int)); /* динамический массив длины М*/

    // Вычисление префикс-функции

    i = 0;
    j = -1;
    d[0] = -1;
    while(i < M-1)
    {
        while((j>=0) && (q[j]!=q[i]))
        {
            j = d[j];
        }
        i++;
        j++;

        if(q[i]==q[j])
        {
            d[i]=d[j];
        } else {
            d[i]= j;
        }
    }

    // поиск
    for(i=0,j=0;(i<N)&&(j<M); i++,j++)
    {
        while((j>=0)&&(q[j]!=s[i]))
        {
            j=d[j];
        }
    }

    free (d);  // освобождение памяти

    if (j==M)
    {
        return i-j;
    } else {
        /* i==N */
        return -1;
    }
}

  Алгоритм Автомата

Пример автомата для шаблона BADBAD:

Автомат позволяет определить есть ли вхождение образца за один проход по строке.
Но постоение самого автомата - задача трудоемкая по времени.

class	AutoMath
{
public:
    char	state;

    AutoMath() : state(0) {} ;
    bool    step(char c);
};

bool AutoMath::step(char c)
{
    switch(state)
    {
    case 0:
        if (c == 'B')
        {
            state = 1;
        }
        break;
    case 1:
        if (c == 'A')
        {
            state = 2;
        } else {
            state = 0;
        }
        break;
    case 2:
        if (c == 'D')
        {
            state = 3;
        } else if (c == 'B')
        {
            state = 1;
        } else {
            state = 0;
        }
        break;
    case 3:
        if (c == 'B')
        {
            state = 4;
        } else {
            state = 0;
        }
        break;
    case 4:
        if (c == 'A')
        {
            state = 4;
        } else if (c == 'B')
        {
            state = 1;
        } else {
            state = 0;
        }
        break;
    case 5:
        if (c == 'D')
        {
            state = 6;
            return	true;
        }
        if (c == 'B')
        {
            state = 1;
        } else {
            state = 0;
        }
        break;
    case 6:
        if (c == 'B')
        {
            state = 4;
        } else {
            state = 0;
        }
        break;
    }
    return	false;
}

bool  strbadbad(char* s)
{
    AutoMath  a;

    while(*s != '\0')
    {
        if (a.step(c)) return true;
        s++;
    }
    return	false;
}

  Выводы

Если шаблон короткий - 2-3 символа - имеет смысл использовать тупой алгоритм.
Будет быстрее.

Если требуется искать один шаблон большое число раз иммет смысл сделать
расшипление алгоритма на 2 части:

    Compile Template	- которая делает предвычисления (делаем 1 раз)
    Apply   Template	- используя результаты предвычисления
                  делает match (вызывается много раз).


70.2.6.2. КОНВЕРТАЦИЯ ЧИСЕЛ В СТРОКИ И ОБРАТНО

  Конвертация чисел в строки и обратно

    Конвертация числа в строку для целых чисел
    Конвертация строки в число для целых чисел
        Форматы чисел
            с указанным основанием
            -12
    Конвертация строки в число и обратно для FP чисел
        в обычном формате
        в экспотенциальном формате
            помним что кроме FP еще бывают и fixed point

    Конвертация для bignums - особенный случай

  Проблематика

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

Прочтите секцию 3.3.СХЕМА ГОРНЕРА И ПРЕОБРАЗОВАНИЯ В ДРУГУЮ СИСТЕМУ СЧИСТЛЕНИЯ

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

void printLowNibble(int n)
{
    n &= 0xf;	// Clear high part

    cout.put((n >= 10)? n + 'a' - 10 : n + '0');
}

void printHexadecimal(int n)
{
    for (int i = sizeof(int) * 8 - 4; i >= 0; i -= 4)
    {
        printLowNibble(n >> i);
    }
}

  Форматы чисел

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

Например представление целых чисел:

десятичная система счисления:
        123		прозрачно, без проблем

двоичная система считления

        1011b		Assembler
        &B1101		BASIC
        0b1101		Perl

восмеричная система счисления

        &O177		BASIC
        0177		C/C++

шестнадцатиричная система счисления:

        0x3f		С/C++
        3fh		Assembler
        $3f		Pascal/Delphi
        &h3f		BASIC
        16r3f		Smalltalk
        16#3f		PostScript
        16^^3f		Mathematica
        8'h3f		Verilog       (в данном случае еще указан и размер - 8бит)

Если пишите стандартную библиотеку для себя, то имеет смысл поддержать несколько стандартных
форматов.
При этом естествнно преобразование (если ему на указали систему счисления должно
делать autio detect.

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

Представления F.P. чисел.

Основные форматы:

    Обычный
        +dddd.dd
        -

    Научный
        +d.dddddd e + ddd
        -         E -

    Шестнадцатиричный
        0x1 hhhhh p hhh
              P

Locale
        123.45	US  (десятичная точка)
        125,45  RU  (десятичная запятая

        (125.12 US  (отрицательные числы в скобках
        -125.12 RU   отрицательные числа без скобок

        123_456.78   разделитель между группами разрядов
        123,456.78

  Конвертация строк в числа

double    atof(const char* str);
int	  atoi(const char* str);
long	  atol(const char* str);

//Формат строки для целых
//	[Spaces][sign][digits]
//

Собственно типовая реализация - через макросы.

#define atof(nptr)  strtod(nptr, (char**) NULL)
#define atoi(nptr)  ((int) strtol(nptr, (char**) NULL, 10))
#define atol(nptr)  strtol(nptr, (char**) NULL, 10)

Как появились 64-разрядные типы пошли дополнительные функции

__int64   atoi64(const char* str);
long long atoll(const char* str);

#define atoll(nptr) strtoll(nptr, (char**) NULL, 10)

Поддержка Wide strings принесла соответсвующие Wide варианты:

double	  _wtof(const wchar_t* str);
int	  _wtoi(const wchar_t* str);
long	  _wtol(const wchar_t* str);
__int64   wtoi64(const wchar_t	* str);

Поддержка Locales порадила новые функции (как обычные так Wide):

// Locale:
int _atoi_l(const char* str, _locale_t locale);

//Locale wide:
int _wtoi_l(const wchar_t* str, _locale_t locale);

Более правильные функции с проверками для float:

int  _atodbl(double* val, char* str);
int  _atoldbl(long double* val, char* str);
int  _atoflt(float* flt, char* str);
    // естественно с wide и locale варианртами

double  strtod(char* nptr, char** endptr)

long	strtol(char* nptr, char** endptr, int base)
unsigned long strtoul(char* nptr, char** endptr, int base);

long long     strtoll(char* nptr, char** endptr, int base);
unsinged long long strtoull(char* nptr, char** endptr, int base);

// flag used by internal function strtouxl():
#define FL_UNSIGNED   1       // INPUT:  unsigned convertion
#define FL_NEG        2       // INTERNAL: number is negative
#define FL_OVERFLOW   4       // INTERNAL: overflow occured
#define FL_READDIGIT  8       // INTERNAL: we read at least one digit

unsigned long strtouxl(const char* nptr, char** endp, int base, int flags)
{
    const char * p;		// current pointer
    char	     c;		// character
    unsigned long number;	// Number
    unsigned long maxval;	// Maximum value
    unsigned     dval;	// Digit value

    assert(nptr != NULL);

    if (endp != NULL)
    {
        *endp = (char*) nptr;
    }

    p = nptr;
    number = 0;

    c = *p++;				// Skip Whitespaces
    while(isspace(c)) c = *p++;

    if (c == '-')				// Get sign if any
    {
        flags |= FL_NEG;
        c = *p++;
    } else if (c == '+')
    {
        c = *p++;
    }

    if (base < 0 || base == 1 || base > 36)  // Check numsys base
    {
        return 0L;
    } else if (base == 0)			 // Autodetect numsys base
    {
        // means, determinate it itself
        if (c != '0')
        {
            base = 10;
        } else if (*p == 'x' || *p == 'X')
        {
            base = 16;
        } else {
            base = 8;
        }
    }

    if (base == 16)				// Skip 0x prefix if hex
    {
        if (c == '0' && (*p == 'x' || *p == 'X'))
        {
            p++;
            c = *p++;	// skip prefix
        }
    }

        maxval = ULONG_MAX / base;

    while(1)				// Main conversion loop
    {
        if (isdigit(c))
        {
            dval = c - '0';
        } else if (isalpha(c))
        {
            dval = toupper(c) - 'A' + 10;
        } else {
            break;
        }

        if (dval >= base) break;

        flags |= FL_READDIGIT;		// we read it least one digit

        if (number < maxval ||
            (number == maxval && (unsigned long) dval <= ULONG_MAX % base))
        {
            // we can't overflow

            number = number * base + dval;
        } else {
            flags |= FL_OVERFLOW;
            if (endp == NULL)
            {
                // we not need keep on parsing
                break;
            }
        }

            c = *p++;               	// read next digit
        }

        --p;          	// point to place that stopped scan

    if (!(flags & FL_READDIGIT))
    {
        // no number was, return 0 and point to begining of string
        if (endp)
        {
            p = nptr;
            number = 0L;
        }
    } else if (flags & FL_OVERFLOW)
    {					// Overflow occured
        errno = ERANGE;
        if (flags & FL_UNSIGNED)
        {
            number = ULONG_MAX;
        } else if (flags & FL_NEG)
        {
            number = (unsigned long) -LONG_MIN;
        } else {
            number = LONG_MAX;
        }
    } else if (!(flags & FL_UNSIGNED))
    {                          		// Overflow for signed occured
        if (flags & FL_NEG)
        {
            if (number > -LONG_MIN)
            {
                errno = ERANGE;
                number = -LONG_MIN;
            }
        } else {
            if (number > LONG_MAX)
            {
                errno = ERANGE;
                number = LONG_MAX;
            }
        }
    }

        if (endp != NULL)
    {
            *endptr = p;
    }

        if (flags & FL_NEG)
    {
            number = (unsigned long)(-(long)number);
    }

        return number;
}

unsigned long strtoul(const char* nptr, char** endp, int base)
{
    return	strtouxl(nptr, endp, base, FL_UNSIGNED);
}

long  strtol(const char* nptr, char** endp, int base)
{
    return  (long) strtouxl(nptr, endp, base, 0);
}

double	wcstod(const wchar_t * str, wchar_t** endptr)
long	wcstol(const wchar_t* str, wchar_t** endp, int base);
unsigned long wcstoul(const wchar_t* str, wchar_t** endp, int base);

Соответсвенно еще в C99 и:

intmax_t  strtoimax(char* nptr, char** endptr, int base);
uintmax_t strtoumax(char* nptr, char** endptr, int base);
intmax_t  wcstoimax(const wchar* str, wchar_t** endp, int base);
uintmax_t wcstoumax(const wchar* str, wchar_t** endp, int base);

  Конвертация чисел в строки

Тупая рекурсивная имплементация:

void printDecimal(int n)
{
    if (n >= 10)
    {
        printDecimal(n / 10);
    }
    cout.put('0' + n % 10);
}

void printInt(int n, int base)
{
    static string DTABLE = "0123456789abcdef";

    if (n >= base)
    {
        printInt(n / base, base);
    }
    cout << DTABLE[n % base];
}

Внутренние функции на которые ложиться нагрузка:

// stdlib.h
char* ecvt(double value, int ndigits, int* decptr, int* sgnptr);
        // value   - number to convert
        // ndigits - number of digits stored
        // decptr  - stored decomal point
        // sgnptr  - sign of converted number
char* fcvt(double value, int ndec,    int* decptr, int* sgnptr);
char* gcvt(double value, int ndec,    char* buffer);

char* itoa(int value, char* string, int radix);
char* ltoa(long value, char* string, int radix);
char* ultoa(unsigned long value, char* str, int radix)

char*  itoa(int value, char* s, int radix)
{
    int	digit;		// Current Digit
    char*	p;		// Working pointer
    char*   firstpos;	// First digit position

    assert(s != NULL);

    if (radix <= 2 || radix  > 36)
    {
        errno = EINVAL;
        *s = '\0';
        return	s;
    }

    p = s;

    if (value < 0)
    {
        *p++ = '-';
        value = -value;
    }

    firstpos = p;

    do				// Place in backward order
    {
        digit = value % radix;
        value /= radix;

        if (digit > 9)
        {
            *p++ = digit + 'a' - 10;
        } else {
            *p++ = digit + '0';
        }
    } while (value > 0);

    *p-- = '\0';

    do				// Reverse in place
    {
        temp = *p;
        *p   = *firstpos;
        *firstpos = temp;
        p--;
        firstpos++;
    } while(firstpos < p);
    return	s;
}


70.2.6.3. ФОРМАТНЫЙ ВЫВОД В СТРОКИ

Какие требования могут быть к выводу числа в строку
        Целое число
        Минимальное количество знаков
        Выравнивание
            Влево
            Вправа
            По центру
        Знак
            Печатать ли + для положительных чисел
            (для отрицательных минус печатается всегда)
        Дополнение влево
            пробелами
            нулями
        Система счисления
        Регистр для букв являющихся цифрами
            нижний
            верхний

  Форматный ввод/вывод

    Форматный вывод в строку

    Форматный вывод в строку

int  __cdecl sprintf(char* buffer, const char* format, ...);

        snprintf
        безопасность - нельзя выходить за пределы строки

int  __cdecl snprintf(char* buffer, size_t maxsize, const char* format, ...);

int  __cdecl wsprintf(LPTSTR buffer, LPCTSTR format, ...);

int  __cdecl swprintf(wchar_t* buffer, size_t count, const wchar_t* format, ...);

int __cdecl vsprintf(char *buffer, const char *format, va_list argptr);
int __cdecl vswprintf(wchar_t *buffer, size_t count, const wchar_t *format, va_list argptr);
int __cdecl vsnprintf(char *buffer, size_t count, const char *format, va_list argptr);
int __cdecl _vsnwprintf(wchar_t *buffer, size_t count, const wchar_t *format, va_list argptr);

    % [flags] [width] [.prec] [ism] type

type is:
    d	signed decimal int
    i	signed decimal int
    o	unsigned octal int
    u	unsigned decimal int
    x	unsigned hexdecimal int (locase)
    X	unsigned hexdecimal int (upcase)
    f	F.P signed [-] dddd.dddd
    e	F.P signed [-] d.dddd or e[+/-]dddd
    g	signed value in float form based on value
    E	same as e, but E for exponent
    G	same as g, but E for exponent
    c	character
    s	string pointer (asciiz)
    %	% character
    n	pointer to int
    p	pointer (format depended on memory model)
        (may be XXXX:XXXX, or XXXXXXXX)

flags is:
    +	justify left results
    -	justify right results
    #	use alternative form
       ' '	if value nonnegative begin with blank, not with +

width is:
    n	at least n characters must be printed
    0n	if output less that n characters, it will padded by zero

ism is:
    F	far pointer
    N	near pointer
    h	short int
    l	long
    L	long double
    I	integer
    ll	long long
    I64	__int64

Проверка формата компилятором:

int printm(char*, ...) __attribute__((const, format(printf,1,2)));

Еще есть разница в трактовке символов и строк для Wide и не-Widе функций

--------------------------------------------
Datatype	printf()	wprintf()
--------------------------------------------
char		%c		%hc
        %hc		%C
        %hC		%hC
--------------------------------------------
wchar_t		%lc		%c
        %C		%lc
        %lC		%lC
--------------------------------------------
char*		%s 		%hs
        %hs		%S
        %hS		%hS
--------------------------------------------
wchar_t*	%ls		%s
        %S		%ls
        %lS		%lS
--------------------------------------------

TODO: C99 intXX_t спецификаторы для sprintf

// Java

Formatter format(String fmtString, Object ... argv);

// Java спецификаторы

    %  [flags] type

flags is:
    -	align left (default: right)
    #	alternative format
    0	padding by 0s (default: spaces)
    +	positive number followed by '+' (default: space)
    ,	use group separators (,)
    (	use brackets for negative numbers

type is:
    a	hexdecimal float locase
    A	hexdecimal float upcase
    b	boolean locase  (true,false)
    B	boolean upcase  (TRUE,FALSE)
    c	character
    d	decimal integer
    h	Hash-code locase
    H	hash-code upcase
    e	scientific notation float locase
    E	scientific notation float upcase
    f	float
    g	'e' or 'f', what is shorter
    G	'E' or 'f', what is shorter
    o	octal integer
    s	string
    S	string upcase
    t	time  (also have suffixes)
    T	time upcased (also have suffixes)
    x	hexdecimal integer lowcase
    X	hexdecimal integer upcase

Использование индексов аргументов

// Java
    2$	второй аргумент
        (пример использования:  %2$d

Можно использовать обе формы одновременно

    fmt.format("%d in hexdecimal is %1$x\n", 255);

Один из приемов - это использование trait-классов для типов,
для того чтобы представлять строки для printf в этих классах:

tempate <class T> class printf_trait
{
public:
    static const char* format_a() { return ""; }
    static const char* format_w() { return ""; }
};

template<>  class printf_trait<char>
{
public:
    static const char* format_a()
    {
        return	"%c";
    }

    static const char* format_w()
    {
        return "%hc";
    }
};

ostream& operator << (ostream& out, const T& val)
{
    ...
    return	out;
}


70.2.6.3.1. DUMP

THIS SECTION IS UNDER CONSTRUCTION

Часто приходиться смотреть содержимое некоторого участка памяти или файла.
Для этого как правило используют текстовое представление в виде dump.


70.2.6.4. СТРОКИ И РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

  Строки и регулярные выражения

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

Мы будем рассматривать примитивные варианты регулярных выражений.

Есть два варианта сравнения:
    template driven
    data	 driven

  Символы и строки

Использование метасимволов как символов:

Некоторые диалекты (Perl) позволяют использовать
стандартные C символы:
    \t	табуляция
    \n	Line Feed
    \r	Carridge Return

  Выбор

  Группы символов

Группа символов - это свой метаязык

Некоторые диалекты (Perl) позволяют испоьзовать
предопределенные классы:
    \s	пробельный символ
        (пробел, TAB, CR, LF, FF etc)
    \S	то что не \s

Другие диалекты (Java) позволяют совершать операции
с группами символов

[[a-z]&&[^aeiou]]	// Java

  POSIX классы символов

[:alnum:]	[A-Za-z0-9]
[:word:]	[A-Za-z0-9_]
[:alpha:]	[A-Za-z]
[:blank:]	[ \t]
[:cntrl:]	[\x00-\x1F\x7F]
[:digit:]	[0-9]
[:graph:]	[\x21-\x7E]
[:lower:]	[a-z]
[:upper:]	[A-Z]
[:print:]	[\x20-\x7E]
[:space:]	[ \t\r\n\v\f]
[:xdigit:]	[A-Fa-f0-9]
[:punct:]	[-!"#$%&'()*+,./:;<=>?@\[\\\]_`{|}~]

  Квантификаторы

  Привязка

Привязка к началу строки

Привязка к конце строки

Привязка к началу концу слова

------------------------
    начало  конец
------------------------
egrep	\<	\>
Perl	\b	\B
------------------------

  Примеры

[a-zA-Z_][a-zA-Z_0-9]*		// идентификатор

"[^"]*"				// строка в кавычках несодержащая внутри \"

^\s+				// Perl: пробельные символы в начале строки

\s+$				// Perl: пробельные символы в конце строки

  Жадность, лень и ревность

При жадном сравнении выбирается сначала как можно большая строка для квантификаторов
При ленивом сравнении выбирается сначала как можно меньшая строка для квантификаторов

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

Жадное	Ленивое	Ревнивое
*	*?	*+
+	+?      ++
{n,}	{n,}?	{n,}+
        ?+

  Perl Extended Regular Expression

(?# comment)
(?:pattern)	кластеризует, но не захватывает в вывод
(?=pattern)	zero-width positive lookahead assertion
(?!pattern)	zero-width negative lookahead assertion
(?<=pattern)	zero-width positive lookbehind assertion
(?pattern)	independed subexpression
(?(condition)yes_pattern|no_pattern)
(?(condtion)yes_pattern)

THIS SECTION IS UNDER CONSTRUCTION

  Регулярные выражения в C++

Стандартом де-факто в Linux и BSD - является библиотека регулярных выражений
созданная Генри Спенсором

int    regcomp(regex_t *preg, const char *pattern, int cflags);
    // компилирует регулярные выражения
    //
    // cflags is:
    //	REG_BASIC (0)	- обычные регулярные выражения
    //	REG_EXTENDED    - расширенные регулярные выражения
    //			  (если хотите использовать a|b - Вам сюда)
    //	REG_ICASE	- ingore case
    //	REG_NOTBOL	- ^ не значит начало строки
    //	REG_NOTEOL	- $ не значит конец строки

int	regexec(const regex_t* preg, const char* string, size_t nmatch,
        regmatch_t pmatch[],  int eflags);

    // выполняет сравнение
    // eflags is:
    //
    //	REG_NOTBOL	00001
    //	REG_NOTEOL	00002
    //	REG_STARTEND	00004
    //	REG_LARGE	01000	/* force large representation */
    //	REG_BACKR	02000	/* force use of backref code */
    //
    // pmatch - массив содержащий информацию о совпадениях:
typedef struct
{
    regoff_t rm_so;		/* start of match */
    regoff_t rm_eo;		/* end of match */
} regmatch_t;

// Regular expression errors:

//      REG_SUCCESS	 0
#define	REG_NOMATCH	 1
#define	REG_BADPAT	 2
#define	REG_ECOLLATE	 3
#define	REG_ECTYPE	 4
#define	REG_EESCAPE	 5
#define	REG_ESUBREG	 6
#define	REG_EBRACK	 7
#define	REG_EPAREN	 8
#define	REG_EBRACE	 9
#define	REG_BADBR	10
#define	REG_ERANGE	11
#define	REG_ESPACE	12
#define	REG_BADRPT	13
#define	REG_EMPTY	14
#define	REG_ASSERT	15
#define	REG_INVARG	16
#define	REG_ENOSYS	17
#define	REG_ATOI	255	/* convert name to number (!) */
#define	REG_ITOA	0400	/* convert number to name (!) */

size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
void   regfree(regex_t *preg);

// проверяет на единичное совпадение с регулярным выражением,
// все ошибки трактуются как несовпадение
bool	strmatch(const char* string, const char* pattern)
{
    regex_t  reg;		// Regular expression structure
    int	 err;		// Error code

    regmatch_t  rm;

    err = regcomp(&reg, pattern, REG_EXTENDED);
    if (err != 0)
    {
        // error on expression compilation
        return	false;
    }

    err = regexec(&reg, string, 1, &rm, 0);
    if (err == REG_NOMATCH)
    {                       	// No match
        regfree(&reg);
        return	false;
    }
    else if (err == 0)
    {				// Match
        regfree(&reg);
        return	true;
    } else {              		// Error
        regfree(&reg);
        return	false;
    }
}

Вторая по популярности библиотека - это PCRE (Perl Compatible Regular expressions).
Она имеет такой же внешний С интерфейс как и библиотека Генри Спенсора.
(только естествнно нескольку другие трактовки некоторых моментов регулярных
выражений, но все равно общая база достаточно большая).

Библиотека Boost также содержит в себе классы для поддержки регулярных выражений над
строками.

Широко известный toolkit Qt тоже содержит класс для работы с регулярными выражениями:

enum CaretMode
{
    CaretAtZero,
    CaretAtOffset,
    CaretWontMatch
}

enum PatternSyntax
{
    RegExp,
    RegExp2,
    Wildcard,
    FixedString
}

class QRegExp
{
public:
    QRegExp();
    QRegExp(const QString & pattern, Qt::CaseSensitivity cs = Qt::CaseSensitive,
            PatternSyntax syntax = RegExp);
    QRegExp(const QRegExp & rx);
    ~QRegExp();

    QString     cap(int nth = 0);
    QStringList capturedTexts();
    Qt::CaseSensitivity caseSensitivity() const;
    QString errorString();
    bool 	exactMatch(const QString& str) const;
    bool 	isEmpty() const;
    bool 	isMinimal() const;
    bool    isValid() const;
    int 	indexIn(const QString& str, int offset=0, CaretMode caretMode = CaretAtZero) const;
    int 	lastIndexIn(const QString& str, int offset=-1, CaretMode caretMode = CaretAtZero) const;
    int 	matchedLength() const;
    int 	numCaptures() const;
    QString pattern() const;
    PatternSyntax patternSyntax() const;
    int 	pos(int nth = 0);
    void 	setCaseSensitivity(Qt::CaseSensitivity cs);
    void 	setMinimal(bool minimal)
    void 	setPattern(const QString & pattern);
    void 	setPatternSyntax (PatternSyntax syntax);

    bool     operator!= (const QRegExp & rx) const;
    QRegExp& operator= (const QRegExp & rx);
    bool     operator==(const QRegExp & rx) const;

static  QString  escape(const QString & str);
};


70.2.6.5. СПИСКИ СТРОК

THIS SECTION IS UNDER CONSTRUCTION

  Списки строк

Списки строк

    простые
        с выделением

    Создать список строк
    Добавить строку в список строк
        в начало	[1]
        в конец         [-1]
        в указанное место (вставить  в строку) [N]
        Вставить пустую строку

    Вставить символ
        [Row, Col]
    Вставить столбец
        [Col]

    Удалить строку
    Удалить столбец
    Удалить символ

    Сортировка списка строк

    Поиск в списке строк
        Поиск подстроки
        Поиск регулярного выражения

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

    TO BE DEFINED LATER
    TODO:  TMemo

  Операции над списками строк

  Вставка строки в начало списка строк

  Вставка строки в конец списка строк

  Вставка строки в указанную позицию списка строк

  Удаление строки из указанной позиции списка строк

  Поиск строки в списке строк

  Поиск подстроки в списке строк

  Сортировка списка строк

  Примеры списков строк

  MFC

class	CStringList : CObject
{
public:
    CStringList( INT_PTR nBlockSize = 10 );

    const CString& GetHead( ) const;
          CString& GetHead( );

    const CString& GetTail( ) const;
              CString& GetTail( );

    POSITION AddHead(const CString& newElement );
    POSITION AddHead(LPCTSTR newElement );
    void AddHead(CStringList* pNewList );

    POSITION AddTail( const CString& newElement );
    POSITION AddTail( LPCTSTR newElement );
    void AddTail( CStringList* pNewList );

    void RemoveAll( );
    CString RemoveHead( );
    CString RemoveTail( );

    POSITION GetHeadPosition( ) const;
    POSITION GetTailPosition( ) const;

    const CString& GetNext( POSITION& rPosition ) const;
          CString& GetNext( POSITION& rPosition );

    const CString& GetPrev( POSITION& rPosition ) const;
          CString& GetPrev( POSITION& rPosition );

    const CString& GetAt( POSITION position ) const;
          CString& GetAt( POSITION position );

    void RemoveAt( POSITION position );
    void SetAt( POSITION pos, const CString& newElement);
    void SetAt( POSITION pos, LPCTSTR newElement );

    POSITION InsertAfter( POSITION position, const CString& newElement );
    POSITION InsertAfter( POSITION position, LPCTSTR newElement );
    POSITION InsertBefore( POSITION position, const CString& newElement );
    POSITION InsertBefore( POSITION position, LPCTSTR newElement );

    POSITION Find( LPCTSTR searchValue, POSITION startAfter = NULL ) const;
    POSITION FindIndex( INT_PTR nIndex ) const;

    INT_PTR GetSize( ) const;
    INT_PTR GetCount( ) const;

    BOOL IsEmpty( ) const;
};

  Delphi TStrings

TStrings - хранение строк и связанных с ними объектов

{ TStrings class }
TStrings = class(TPersistent)
private
        FDefined: TStringsDefined;
        FDelimiter: Char;
        FQuoteChar: Char;
        FUpdateCount: Integer;
        FAdapter: IStringsAdapter;
        function GetCommaText: string;
        function GetDelimitedText: string;
        function GetName(Index: Integer): string;
        function GetValue(const Name: string): string;
        procedure ReadData(Reader: TReader);
        procedure SetCommaText(const Value: string);
        procedure SetDelimitedText(const Value: string);
        procedure SetStringsAdapter(const Value: IStringsAdapter);
        procedure SetValue(const Name, Value: string);
        procedure WriteData(Writer: TWriter);
        function GetDelimiter: Char;
        procedure SetDelimiter(const Value: Char);
        function GetQuoteChar: Char;
        procedure SetQuoteChar(const Value: Char);
protected
        procedure DefineProperties(Filer: TFiler); override;
        procedure Error(const Msg: string; Data: Integer); overload;
        procedure Error(Msg: PResStringRec; Data: Integer); overload;
        function ExtractName(const S: string): string;
        function Get(Index: Integer): string; virtual; abstract;
        function GetCapacity: Integer; virtual;
        function GetCount: Integer; virtual; abstract;
        function GetObject(Index: Integer): TObject; virtual;
        function GetTextStr: string; virtual;
        procedure Put(Index: Integer; const S: string); virtual;
        procedure PutObject(Index: Integer; AObject: TObject); virtual;
        procedure SetCapacity(NewCapacity: Integer); virtual;
        procedure SetTextStr(const Value: string); virtual;
        procedure SetUpdateState(Updating: Boolean); virtual;
        property UpdateCount: Integer read FUpdateCount;
        function CompareStrings(const S1, S2: string): Integer; virtual;
public
        destructor Destroy; override;
        function Add(const S: string): Integer; virtual;
        function AddObject(const S: string; AObject: TObject): Integer; virtual;
        procedure Append(const S: string);
        procedure AddStrings(Strings: TStrings); virtual;
        procedure Assign(Source: TPersistent); override;
        procedure BeginUpdate;
        procedure Clear; virtual; abstract;
        procedure Delete(Index: Integer); virtual; abstract;
        procedure EndUpdate;
        function Equals(Strings: TStrings): Boolean;
        procedure Exchange(Index1, Index2: Integer); virtual;
        function GetText: PChar; virtual;
        function IndexOf(const S: string): Integer; virtual;
        function IndexOfName(const Name: string): Integer; virtual;
        function IndexOfObject(AObject: TObject): Integer; virtual;
        procedure Insert(Index: Integer; const S: string); virtual; abstract;
        procedure InsertObject(Index: Integer; const S: string; AObject: TObject); virtual;
        procedure LoadFromFile(const FileName: string); virtual;
        procedure LoadFromStream(Stream: TStream); virtual;
        procedure Move(CurIndex, NewIndex: Integer); virtual;
        procedure SaveToFile(const FileName: string); virtual;
        procedure SaveToStream(Stream: TStream); virtual;
        procedure SetText(Text: PChar); virtual;
        property Capacity: Integer read GetCapacity write SetCapacity;
        property CommaText: string read GetCommaText write SetCommaText;
        property Count: Integer read GetCount;
        property Delimiter: Char read GetDelimiter write SetDelimiter;
        property DelimitedText: string read GetDelimitedText write SetDelimitedText;
        property Names[Index: Integer]: string read GetName;
        property Objects[Index: Integer]: TObject read GetObject write PutObject;
        property QuoteChar: Char read GetQuoteChar write SetQuoteChar;
        property Values[const Name: string]: string read GetValue write SetValue;
        property Strings[Index: Integer]: string read Get write Put; default;
        property Text: string read GetTextStr write SetTextStr;
       property StringsAdapter: IStringsAdapter read FAdapter write SetStringsAdapter;
end;

TStringList - класс для хранения списков строк

{ TStringList class }

TStringList = class;

PStringItem = ^TStringItem;
TStringItem = record
    FString: string;
    FObject: TObject;
end;

PStringItemList = ^TStringItemList;
TStringItemList = array[0..MaxListSize] of TStringItem;
TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;

TStringList = class(TStrings)
private
        FList: PStringItemList;
        FCount: Integer;
        FCapacity: Integer;
        FSorted: Boolean;
        FDuplicates: TDuplicates;
        FCaseSensitive: Boolean;
        FOnChange: TNotifyEvent;
        FOnChanging: TNotifyEvent;
        procedure ExchangeItems(Index1, Index2: Integer);
        procedure Grow;
        procedure QuickSort(L, R: Integer; SCompare: TStringListSortCompare);
        procedure SetSorted(Value: Boolean);
        procedure SetCaseSensitive(const Value: Boolean);
protected
        procedure Changed; virtual;
        procedure Changing; virtual;
        function Get(Index: Integer): string; override;
        function GetCapacity: Integer; override;
        function GetCount: Integer; override;
        function GetObject(Index: Integer): TObject; override;
        procedure Put(Index: Integer; const S: string); override;
        procedure PutObject(Index: Integer; AObject: TObject); override;
        procedure SetCapacity(NewCapacity: Integer); override;
        procedure SetUpdateState(Updating: Boolean); override;
        function CompareStrings(const S1, S2: string): Integer; override;
        procedure InsertItem(Index: Integer; const S: string; AObject: TObject); virtual;
public
        destructor Destroy; override;
        function Add(const S: string): Integer; override;
        function AddObject(const S: string; AObject: TObject): Integer; override;
        procedure Clear; override;
        procedure Delete(Index: Integer); override;
        procedure Exchange(Index1, Index2: Integer); override;
        function Find(const S: string; var Index: Integer): Boolean; virtual;
        function IndexOf(const S: string): Integer; override;
        procedure Insert(Index: Integer; const S: string); override;
        procedure InsertObject(Index: Integer; const S: string; AObject: TObject); override;
        procedure Sort; virtual;
        procedure CustomSort(Compare: TStringListSortCompare); virtual;
        property Duplicates: TDuplicates read FDuplicates write FDuplicates;
        property Sorted: Boolean read FSorted write SetSorted;
        property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive;
        property OnChange: TNotifyEvent read FOnChange write FOnChange;
        property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
end;

  Qt QStringList

class  QStringList : public QList<QString>
{
public:
    QStringList();
    QStringList(const QString& str);
    QStringList(const QStringList& other);
    QStringList(const QList<QString>& other);

    bool 	     contains(const QString& str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    QStringList  filter(const QString & str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    QStringList  filter(const QRegExp & rx) const;
    int          indexOf (const QRegExp & rx, int from = 0) const;
    QString      join (const QString & separator) const;
    int          lastIndexOf (const QRegExp& rx, int from = -1) const;
    QStringList& replaceInStrings(const QString& before, const QString& after,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive);
    QStringList& replaceInStrings(const QRegExp& rx, const QString& after );
    void         sort();
    QStringList  operator+  (const QStringList& other) const;
    QStringList& operator<< (const QString& str);
    QStringList& operator<< (const QStringList& other);
};

class QListIterator
{
public:
    QListIterator(const QList<T>& list);

    bool 	 findNext(const T &value);
    bool 	 findPrevious(const T& value);
    bool 	 hasNext() const;
    bool 	 hasPrevious() const;
    const T& next();
    const T& peekNext() const;
    const T& peekPrevious() const;
    const T& previous();
    void 	 toBack();
    void 	 toFront();
    QListIterator & operator= (const QList<T>& list);
};

class QList
{
public:
    // Definitons
    class const_iterator
    class iterator
    typedef ConstIterator
    typedef Iterator
    typedef const_pointer
    typedef const_reference
    typedef difference_type
    typedef pointer
    typedef reference
    typedef size_type
    typedef value_type

    QList();
    QList(const QList<T> & other);
    ~QList();
    void 	  append(const T& value);
    const T&  at(int i) const;
    T& 	  back()
    const T&  back() const
    iterator  begin();
    const_iterator begin() const;
    void 	 clear();
    const_iterator constBegin() const;
    const_iterator constEnd() const;
    bool 	 contains(const T& value) const;
    int 	 count(const T& value) const;
    int 	 count() const;
    bool 	 empty() const;
    iterator end();
    const_iterator end() const;
    iterator erase(iterator pos);
    iterator erase(iterator begin, iterator end);
    T& 	 first ();
    const T& first() const;
    T& 	 front();
    const T& front() const;
    int 	 indexOf(const T& value, int from = 0) const;
    void 	 insert(int i, const T& value);
    iterator insert(iterator before, const T& value);
    bool 	 isEmpty() const;
    T& 	 last();
    const T& last() const;
    int 	 lastIndexOf(const T& value, int from = -1) const;
    QList<T> mid(int pos, int length = -1) const;
    void 	 move(int from, int to);
    void 	 pop_back();
    void 	 pop_front();
    void 	 prepend(const T& value);
    void 	 push_back(const T& value);
    void	 push_front(const T& value);
    int 	 removeAll(const T& value);
    void 	 removeAt(int i);
    void 	 removeFirst();
    void 	 removeLast();
    void 	 replace(int i, const T& value);
    int 	 size () const;
    void 	 swap(int i, int j);
    T 	 takeAt(int i);
    T 	 takeFirst();
    T 	 takeLast ();
    QSet<T>      toSet() const;
    std::list<T> toStdList () const;
    QVector<T>   toVector() const;
    T 	value(int i) const;
    T 	value(int i, const T& defaultValue) const;
    bool      operator!= (const QList<T>& other) const;
    QList<T>  operator+ (const QList<T>& other) const;
    QList<T>& operator+= (const QList<T>& other);
    QList<T>& operator+= (const T& value);
    QList<T>& operator<< (const QList<T>& other);
    QList<T>& operator<< (const T& value);
    QList<T>& operator= (const QList<T>& other);
    bool      operator== (const QList<T>& other) const;
    T&        operator[] (int i);
    const T&  operator[] (int i) const;

static  QList<T> fromSet(const QSet<T>& set);
static  QList<T> fromStdList(const std::list<T>& list);
static	QList<T> fromVector(const QVector<T>& vector);
};

  Выделение в списке строк

    Выделение области
        Линейная  (startX, startY, endX, endY)
            так же можно выделить и сами строки
              (0, startY, 0, endY)
        Прямоугольная (startX, startY, endX, endY)

собственно разная семантика трактовки в этих двух случаях.

  Линейное выделение в списке строк

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

  Операции с выделенной зоной в списке строк

    Получить выделенную зону  (Get)
    Заменить выделенную зону  (Replace)

    Собсвенно операции типа
        Copy
        Paste
        Cut
    делаются через эти примитивы

    (наиболее интересный вариант - это прямоугольная зона)

  Расщепление и соединение строк

  Расщепление строки на подстроки

//С#
    string[] Split(char[])
    string[] Split(char[], int)

// libpub

int  strsplit(char* s, char** words, int maxw, const char* sep);

  Сборка строки из подстрок

//C#
    string Join(string, string[])
    string Join(string, string[], int, int)


70.2.6.6. ПОТОКОБЕЗОПАСНЫЕ СТРОКИ

Как сделать строки потокобезопасными?
В  С    - никак.
В  С++  - придеться стараться:

    Во первых операции над строками деляться на 2 группы
        изменяющие строки
        неизменяющие строки
            c счетчиком ссылок

    Поэтому для синхронизации имеет смысл использовать RWLock
    В самой структуре для строки можно сделать поле RWLock
    внутри функций можно сразу конструировать соответсвующие locker классы.

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

    Через proxy object - который будет делать lock для строки.

    class MyString
    {
    public:
        ProxyObject  GetString();

        class ProxyObject
        {
            ProxyObject(MyString& str)
            {
                ReaderLock(str.rwlock);
            }

            ~ProxyObject()
            {
                ReaderUnlock(str.rwlock);
            }

            operator char*()
            {
                 return	GetStringBuffer();
            }
        }
    private:
        char*	     GetStringBuffer();
    };

    MyString x("filename");

    fileOpen(x.GetString());	// отработает, так как временный объект
                    // будет жить до возврата функции.

    Но если вы хотите хранить данные которые вам возвращает GetString(),
    то вам надо их скопировать.


70.2.6.7. ТИПОВЫЕ СТРОКОВЫЕ ИНТЕРФЕЙСЫ

В этой секции приведены типовые широкоиспользуемые интерфейсы для строк:

    o  Qt QString
    o  MFC CString
    o  C++ STL std::string
    o  Java  java.lang.string
    o  C# CLR  System.String
    o  Delphi RTL для строк
    o  Windows NT Kernel Mode RTL для строк

  Qt QString

Qt QString - это один из наиболее элегантных строковых классов в индустрии.

На что следует обратить внимание:
    - Поддержка других форматов строк при операциях
    - Встроенные преобразования в/из стандарных числовых типов
    - Встроенный форматный вывод (sprintf)
    - Богатая коллекция примитивов

enum NormalizationForm
{
    NormalizationForm_D,
    NormalizationForm_C,
    NormalizationForm_KD,
    NormalizationForm_KC
}

enum SectionFlag
{
    SectionDefault,
    SectionSkipEmpty,
    SectionIncludeLeadingSep,
    SectionIncludeTrailingSep,
    SectionCaseInsensitiveSeps
}

enum SplitBehavior
{
    KeepEmptyParts,
    SkipEmptyParts
}

class QString
{
public:
    QString();
    QString(const QChar* unicode, int size);
    QString(QChar ch);
    QString(int size, QChar ch);
    QString(const QLatin1String& str);	// from one byte string
    QString(const QString& other);

QT_ASCII_CAST_WARN_CONSTRUCTOR QString(const char* str);
QT_ASCII_CAST_WARN_CONSTRUCTOR QString(const QByteArray& ba);

    ~QString ();

    QString& append(const QString& str);
    QString& append(const QLatin1String& str);
    QString& append(const QByteArray& ba);
    QString& append(const char* str);
    QString& append(QChar ch);
    QString& prepend(const QString& str);		// add to start of string
    QString& prepend(const QLatin1String& str);
    QString& prepend(const QByteArray& ba);
    QString& prepend(const char* str);
    QString& prepend(QChar ch);

    QString arg(const QString& a, int fieldWidth = 0,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(const QString& a1, const QString& a2) const;
    QString arg(const QString& a1, const QString& a2, const QString& a3) const;
    QString arg(const QString& a1, const QString& a2, const QString& a3, const QString& a4) const;
    QString arg(int a, int fieldWidth = 0, int base = 10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(uint a, int fieldWidth=0, int base=10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(long a, int fieldWidth=0, int base=10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(ulong a, int fieldWidth=0, int base=10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(qlonglong a, int fieldWidth=0, int base=10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(qulonglong a, int fieldWidth=0, int base=10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(short a, int fieldWidth=0, int base=10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(ushort a, int fieldWidth=0, int base=10,
            const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(QChar a, int fieldWidth=0, const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(char a, int fieldWidth=0, const QChar& fillChar = QLatin1Char(' ')) const;
    QString arg(double a, int fieldWidth=0, char format = 'g', int precision = -1,
           const QChar & fillChar = QLatin1Char( ' ' ) ) const;

  const QChar 	 at(int position) const;
    int 	 capacity() const;
    void 	 chop(int n);
    void 	 clear();

    int 	 compare(const QString& other) const;
    int 	 compare(const QString& other, Qt::CaseSensitivity cs) const;
    int 	 compare(const QLatin1String& other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    int 	 localeAwareCompare(const QString& other) const;

    bool 	 contains(const QString& str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool 	 contains(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool 	 contains(const QRegExp& rx) const;
    int 	 count(const QString & str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    int 	 count(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    int 	 count(const QRegExp& rx) const;
    int 	 count() const;

  const QChar* 	 constData() const;
    QChar* 	 data();
  const QChar*   data() const;

    QString& fill(QChar ch, int size = -1);

    int 	 indexOf(const QString& str, int from = 0,
             Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    int 	 indexOf(QChar ch, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    int 	 indexOf(const QRegExp & rx, int from = 0) const;
    int 	 lastIndexOf(const QString& str, int from = -1,
                 Qt::CaseSensitivity cs = Qt::CaseSensitive ) const;
    int 	 lastIndexOf(QChar ch, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    int 	 lastIndexOf(const QRegExp& rx, int from = -1) const;

    QString& insert(int position, const QString & str);
    QString& insert(int position, const QLatin1String & str);
    QString& insert(int position, const QChar* unicode, int size);
    QString& insert(int position, QChar ch);

    bool 	 isEmpty() const;
    bool 	 isNull() const;
    int 	 length() const;

    QString  normalized(NormalizationForm form) const;
    QString  normalized(NormalizationForm form, QChar::UnicodeVersion version) const;

    void 	 push_back(const QString& other);
    void 	 push_back(QChar ch);
    void     push_front(const QString & other);
    void     push_front(QChar ch);

    QString& remove(int position, int n);
    QString& remove(const QString& str, Qt::CaseSensitivity cs = Qt::CaseSensitive);
    QString& remove(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive);
    QString& remove(const QRegExp& rx);

    QString& replace(int position, int n, const QString& after);
    QString& replace(int position, int n, const QChar* unicode, int size);
    QString& replace(int position, int n, QChar after);
    QString& replace(const QString& before, const QString& after,
             Qt::CaseSensitivity cs = Qt::CaseSensitive);
    QString& replace(QChar ch, const QString& after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
    QString& replace(QChar before, QChar after, Qt::CaseSensitivity cs = Qt::CaseSensitive )
    QString& replace(const QRegExp& rx, const QString& after);

    QString  left(int n) const;
    QString  mid(int position, int n = -1) const;
    QString  right (int n) const;

    QString  rightJustified(int width, QChar fill = QLatin1Char(' '), bool truncate = false) const;
    QString  leftJustified (int width, QChar fill = QLatin1Char(' '), bool truncate = false) const;

    QString  section(QChar sep, int start, int end = -1, SectionFlags flags = SectionDefault) const;
    QString  section(const QString& sep, int start, int end = -1,
             SectionFlags flags = SectionDefault ) const;
    QString  section(const QRegExp& reg, int start, int end = -1,
             SectionFlags flags = SectionDefault ) const;

    QString& setNum(int n, int base = 10);
    QString& setNum(uint n, int base = 10);
    QString& setNum(long n, int base = 10);
    QString& setNum(ulong n, int base = 10);
    QString& setNum(qlonglong n, int base = 10);
    QString& setNum(qulonglong n, int base = 10);
    QString& setNum(short n, int base = 10);
    QString& setNum(ushort n, int base = 10);
    QString& setNum(double n, char format = 'g', int precision = 6);
    QString& setNum(float n, char format = 'g', int precision = 6);

    QString& setUnicode(const QChar* unicode, int size);
    QString& setUtf16(const ushort * unicode, int size);

    QStringList split(const QString& sep, SplitBehavior behavior = KeepEmptyParts,
              Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    QStringList split(const QChar& sep, SplitBehavior behavior = KeepEmptyParts,
              Qt::CaseSensitivity cs = Qt::CaseSensitive ) const;
    QStringList split(const QRegExp& rx, SplitBehavior behavior = KeepEmptyParts) const;

    bool     startsWith(const QString& s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool     startsWith(const QLatin1String& s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool     startsWith(const QChar& c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool 	 endsWith(const QString& s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool 	 endsWith(const QLatin1String& s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool 	 endsWith(const QChar& c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    QString    toLower() const;
    QString    toUpper() const;

    int 	   size() const;
    void 	   squeeze();		// release memory not required for store data
    void 	   reserve(int size);
    void 	   resize(int size);

    QString    simplified() const; 	// remove escape '\x' characters
    QString    trimmed() const;
    void 	   truncate(int position);

    double 	   toDouble(bool* ok = 0) const;
    float      toFloat(bool* ok = 0) const;
    int 	   toInt(bool* ok = 0, int base = 10) const;
    long 	   toLong(bool* ok = 0, int base = 10) const;
    qlonglong  toLongLong(bool* ok = 0, int base = 10) const;
    short 	   toShort(bool* ok = 0, int base = 10) const;

    uint 	   toUInt(bool* ok = 0, int base = 10) const;
    ulong 	   toULong(bool* ok = 0, int base = 10) const;
    qulonglong toULongLong(bool* ok = 0, int base = 10) const;
    ushort     toUShort(bool* ok = 0, int base = 10) const;

    QByteArray toAscii() const;
    QByteArray toLatin1() const;
    QByteArray toLocal8Bit() const;
    std::string  toStdString() const;
    std::wstring toStdWString() const;
    QVector<uint> toUcs4() const;
    QByteArray toUtf8() const;
    int 	   toWCharArray(wchar_t* array) const;

    const QChar*  unicode() const;
    const ushort* utf16() const;

    QString& sprintf(const char* cformat, ...);
    QString&   vsprintf (const char * cformat, va_list ap);

    QString&   operator += (const QString& other);
    QString&   operator += (const QLatin1String& str);
    QString&   operator += (const QByteArray& ba);
    QString&   operator += (const char* str);
    QString&   operator += (char ch);
    QString&   operator += (QChar ch);

    bool 	   operator != (const QString& other) const;
    bool       operator != (const QLatin1String& other) const;
    bool       operator != (const QByteArray& other) const;
    bool       operator != (const char* other) const;
    bool       operator == (const QString& other) const;
    bool       operator == (const QLatin1String& other) const;
    bool       operator == (const QByteArray& other) const;
    bool       operator == (const char* other) const;
    bool       operator < (const QString& other) const;
    bool       operator < (const QLatin1String& other) const;
    bool       operator < (const QByteArray& other) const;
    bool       operator < (const char* other) const;
    bool       operator <= (const QString& other) const;
    bool       operator <= (const QLatin1String& other) const;
    bool       operator <= (const QByteArray& other) const;
    bool       operator <= (const char* other) const;
    bool       operator > (const QString& other) const;
    bool       operator > (const QLatin1String& other) const;
    bool       operator > (const QByteArray& other) const;
    bool       operator > (const char* other) const;
    bool       operator >= (const QString& other) const;
    bool       operator >= (const QLatin1String& other) const;
    bool       operator >= (const QByteArray& other) const;
    bool       operator >= (const char* other) const;

    QString&   operator = (const QString& other);
    QString&   operator = (const QLatin1String& str);
    QString&   operator = (const QByteArray& ba);
    QString&   operator = (const char* str);
    QString&   operator = (char ch);
    QString&   operator = (QChar ch);

    QCharRef   operator[] (int position);
  const QChar 	   operator[] (int position) const;
    QCharRef   operator[] (uint position);
  const QChar      operator[] (uint position) const;

static	int     compare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs);
static	int     compare(const QString& s1, const QString& s2);
static	int     compare(const QString& s1, const QLatin1String & s2,
                Qt::CaseSensitivity cs = Qt::CaseSensitive);
static	int     compare(const QLatin1String& s1, const QString & s2,
            Qt::CaseSensitivity cs = Qt::CaseSensitive);

static	QString fromAscii(const char* str, int size = -1);
static	QString fromLatin1(const char* str, int size = -1);
static	QString fromLocal8Bit(const char* str, int size = -1);
static	QString fromRawData(const QChar* unicode, int size);
static	QString fromStdString(const std::string& str);
static	QString fromStdWString(const std::wstring& str);
static	QString fromUcs4(const uint* unicode, int size = -1);
static	QString fromUtf8(const char* str, int size = -1);
static	QString fromUtf16(const ushort* unicode, int size = -1);
static	QString fromWCharArray(const wchar_t* string, int size = -1);

static	int     localeAwareCompare(const QString & s1, const QString& s2 )

static	QString number(long n, int base = 10);
static	QString number(ulong n, int base = 10);
static	QString number(int n, int base = 10);
static	QString number(uint n, int base = 10);
static	QString number(qlonglong n, int base = 10);
static	QString number(qulonglong n, int base = 10);
static	QString number(double n, char format = 'g', int precision = 6);

};

// Non-members

const QString operator + (const QString& s1, const QString& s2);
const QString operator + (const QString& s1, const char* s2);
const QString operator + (const char* s1, const QString& s2);
const QString operator + (const QString& s, char ch);
const QString operator + (char ch, const QString& s);

      bool    operator != (const char* s1, const QString& s2);
      bool    operator < (const char* s1, const QString& s2);
      bool    operator <= (const char* s1, const QString& s2);
      bool    operator == (const char* s1, const QString& s2);
      bool    operator > (const char* s1, const QString& s2);
      bool    operator >= (const char* s1, const QString& s2);

QDataStream & operator>> ( QDataStream & stream, QString& string);
QDataStream & operator<< ( QDataStream & stream, const QString& string);

  MFC

class CString
{
public:
// Constructors

    // constructs empty CString
    CString();
    // copy constructor
    CString(const CString& stringSrc);
    // from a single character
    CString(TCHAR ch, int nRepeat = 1);
    // from an ANSI string (converts to TCHAR)
    CString(LPCSTR lpsz);
    // from a UNICODE string (converts to TCHAR)
    CString(LPCWSTR lpsz);
    // subset of characters from an ANSI string (converts to TCHAR)
    CString(LPCSTR lpch, int nLength);
    // subset of characters from a UNICODE string (converts to TCHAR)
    CString(LPCWSTR lpch, int nLength);
    // from unsigned characters
    CString(const unsigned char* psz);

// Attributes & Operations

    // get data length
    int GetLength() const;
    // TRUE if zero length
    BOOL IsEmpty() const;
    // clear contents to empty
    void Empty();

    // return single character at zero-based index
    TCHAR GetAt(int nIndex) const;
    // return single character at zero-based index
    TCHAR operator[](int nIndex) const;
    // set a single character at zero-based index
    void SetAt(int nIndex, TCHAR ch);
    // return pointer to const string
    operator LPCTSTR() const;

    // overloaded assignment

    // ref-counted copy from another CString
    const CString& operator=(const CString& stringSrc);
    // set string content to single character
    const CString& operator=(TCHAR ch);
#ifdef _UNICODE
    const CString& operator=(char ch);
#endif
    // copy string content from ANSI string (converts to TCHAR)
    const CString& operator=(LPCSTR lpsz);
    // copy string content from UNICODE string (converts to TCHAR)
    const CString& operator=(LPCWSTR lpsz);
    // copy string content from unsigned chars
    const CString& operator=(const unsigned char* psz);

    // string concatenation

    // concatenate from another CString
    const CString& operator+=(const CString& string);

    // concatenate a single character
    const CString& operator+=(TCHAR ch);
#ifdef _UNICODE
    // concatenate an ANSI character after converting it to TCHAR
    const CString& operator+=(char ch);
#endif
    // concatenate a UNICODE character after converting it to TCHAR
    const CString& operator+=(LPCTSTR lpsz);

    friend CString AFXAPI operator+(const CString& string1,
            const CString& string2);
    friend CString AFXAPI operator+(const CString& string, TCHAR ch);
    friend CString AFXAPI operator+(TCHAR ch, const CString& string);
#ifdef _UNICODE
    friend CString AFXAPI operator+(const CString& string, char ch);
    friend CString AFXAPI operator+(char ch, const CString& string);
#endif
    friend CString AFXAPI operator+(const CString& string, LPCTSTR lpsz);
    friend CString AFXAPI operator+(LPCTSTR lpsz, const CString& string);

    // string comparison

    // straight character comparison
    int Compare(LPCTSTR lpsz) const;
    // compare ignoring case
    int CompareNoCase(LPCTSTR lpsz) const;
    // NLS aware comparison, case sensitive
    int Collate(LPCTSTR lpsz) const;
    // NLS aware comparison, case insensitive
    int CollateNoCase(LPCTSTR lpsz) const;

    // simple sub-string extraction

    // return nCount characters starting at zero-based nFirst
    CString Mid(int nFirst, int nCount) const;
    // return all characters starting at zero-based nFirst
    CString Mid(int nFirst) const;
    // return first nCount characters in string
    CString Left(int nCount) const;
    // return nCount characters from end of string
    CString Right(int nCount) const;

    //  characters from beginning that are also in passed string
    CString SpanIncluding(LPCTSTR lpszCharSet) const;
    // characters from beginning that are not also in passed string
    CString SpanExcluding(LPCTSTR lpszCharSet) const;

    // upper/lower/reverse conversion

    // NLS aware conversion to uppercase
    void MakeUpper();
    // NLS aware conversion to lowercase
    void MakeLower();
    // reverse string right-to-left
    void MakeReverse();

    // trimming whitespace (either side)

    // remove whitespace starting from right edge
    void TrimRight();
    // remove whitespace starting from left side
    void TrimLeft();

    // trimming anything (either side)

    // remove continuous occurrences of chTarget starting from right
    void TrimRight(TCHAR chTarget);
    // remove continuous occcurrences of characters in passed string,
    // starting from right
    void TrimRight(LPCTSTR lpszTargets);
    // remove continuous occurrences of chTarget starting from left
    void TrimLeft(TCHAR chTarget);
    // remove continuous occcurrences of characters in
    // passed string, starting from left
    void TrimLeft(LPCTSTR lpszTargets);

    // advanced manipulation

    // replace occurrences of chOld with chNew
    int Replace(TCHAR chOld, TCHAR chNew);
    // replace occurrences of substring lpszOld with lpszNew;
    // empty lpszNew removes instances of lpszOld
    int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew);
    // remove occurrences of chRemove
    int Remove(TCHAR chRemove);
    // insert character at zero-based index; concatenates
    // if index is past end of string
    int Insert(int nIndex, TCHAR ch);
    // insert substring at zero-based index; concatenates
    // if index is past end of string
    int Insert(int nIndex, LPCTSTR pstr);
    // delete nCount characters starting at zero-based index
    int Delete(int nIndex, int nCount = 1);

    // searching

    // find character starting at left, -1 if not found
    int Find(TCHAR ch) const;
    // find character starting at right
    int ReverseFind(TCHAR ch) const;
    // find character starting at zero-based index and going right
    int Find(TCHAR ch, int nStart) const;
    // find first instance of any character in passed string
    int FindOneOf(LPCTSTR lpszCharSet) const;
    // find first instance of substring
    int Find(LPCTSTR lpszSub) const;
    // find first instance of substring starting at zero-based index
    int Find(LPCTSTR lpszSub, int nStart) const;

    // simple formatting

    // printf-like formatting using passed string
    void AFX_CDECL Format(LPCTSTR lpszFormat, ...);
    // printf-like formatting using referenced string resource
    void AFX_CDECL Format(UINT nFormatID, ...);
    // printf-like formatting using variable arguments parameter
    void FormatV(LPCTSTR lpszFormat, va_list argList);

    // formatting for localization (uses FormatMessage API)

    // format using FormatMessage API on passed string
    void AFX_CDECL FormatMessage(LPCTSTR lpszFormat, ...);
    // format using FormatMessage API on referenced string resource
    void AFX_CDECL FormatMessage(UINT nFormatID, ...);

    friend CArchive& AFXAPI operator<<(CArchive& ar, const CString& string);
    friend CArchive& AFXAPI operator>>(CArchive& ar, CString& string);

    // load from string resource
    BOOL LoadString(UINT nID);

#ifndef _UNICODE
    // ANSI <-> OEM support (convert string in place)

    // convert string from ANSI to OEM in-place
    void AnsiToOem();
    // convert string from OEM to ANSI in-place
    void OemToAnsi();
#endif

#ifndef _AFX_NO_BSTR_SUPPORT
    // OLE BSTR support (use for OLE automation)

    // return a BSTR initialized with this CString&apos;s data
    BSTR AllocSysString() const;
    // reallocates the passed BSTR, copies content of this CString to it
    BSTR SetSysString(BSTR* pbstr) const;
#endif

    // Access to string implementation buffer as "C" character array

    // get pointer to modifiable buffer at least as long as nMinBufLength
    LPTSTR GetBuffer(int nMinBufLength);
    // release buffer, setting length to nNewLength (or to first nul if -1)
    void ReleaseBuffer(int nNewLength = -1);
    // get pointer to modifiable buffer exactly as long as nNewLength
    LPTSTR GetBufferSetLength(int nNewLength);
    // release memory allocated to but unused by string
    void FreeExtra();

    // Use LockBuffer/UnlockBuffer to turn refcounting off

    // turn refcounting back on
    LPTSTR LockBuffer();
    // turn refcounting off
    void UnlockBuffer();

// Implementation
public:
    ~CString();
    int GetAllocLength() const;

protected:
    LPTSTR m_pchData;   // pointer to ref counted string data

    // implementation helpers
    CStringData* GetData() const;
    void Init();
    void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
    void AllocBuffer(int nLen);
    void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
    void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data);
    void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
    void CopyBeforeWrite();
    void AllocBeforeWrite(int nLen);
    void Release();
    static void PASCAL Release(CStringData* pData);
    static int PASCAL SafeStrlen(LPCTSTR lpsz);
    static void FASTCALL FreeData(CStringData* pData);
};

// Compare helpers
bool AFXAPI operator==(const CString& s1, const CString& s2);
bool AFXAPI operator==(const CString& s1, LPCTSTR s2);
bool AFXAPI operator==(LPCTSTR s1, const CString& s2);
bool AFXAPI operator!=(const CString& s1, const CString& s2);
bool AFXAPI operator!=(const CString& s1, LPCTSTR s2);
bool AFXAPI operator!=(LPCTSTR s1, const CString& s2);
bool AFXAPI operator<(const CString& s1, const CString& s2);
bool AFXAPI operator<(const CString& s1, LPCTSTR s2);
bool AFXAPI operator<(LPCTSTR s1, const CString& s2);
bool AFXAPI operator>(const CString& s1, const CString& s2);
bool AFXAPI operator>(const CString& s1, LPCTSTR s2);
bool AFXAPI operator>(LPCTSTR s1, const CString& s2);
bool AFXAPI operator<=(const CString& s1, const CString& s2);
bool AFXAPI operator<=(const CString& s1, LPCTSTR s2);
bool AFXAPI operator<=(LPCTSTR s1, const CString& s2);
bool AFXAPI operator>=(const CString& s1, const CString& s2);
bool AFXAPI operator>=(const CString& s1, LPCTSTR s2);
bool AFXAPI operator>=(LPCTSTR s1, const CString& s2);

// CStringData - class, where CString keep string data
struct CStringData
{
    long nRefs;             // reference count
    int nDataLength;        // length of data (including terminator)
    int nAllocLength;       // length of allocation
    // TCHAR data[nAllocLength]

    TCHAR* data()           // TCHAR* to managed data
        { return (TCHAR*)(this+1); }
};

  C++ std::string

template<class _E,
    class _Tr = char_traits<_E>,
    class _A = allocator<_E> >
    class basic_string {
public:
    typedef basic_string<_E, _Tr, _A> _Myt;
    typedef _A::size_type size_type;
    typedef _A::difference_type difference_type;
    typedef _A::pointer pointer;
    typedef _A::const_pointer const_pointer;
    typedef _A::reference reference;
    typedef _A::const_reference const_reference;
    typedef _A::value_type value_type;
    typedef _A::pointer iterator;
    typedef _A::const_pointer const_iterator;
    typedef reverse_iterator<const_iterator, value_type,
        const_reference, const_pointer, difference_type>
            const_reverse_iterator;
    typedef reverse_iterator<iterator, value_type,
        reference, pointer, difference_type>
            reverse_iterator;
    explicit basic_string(const _A& _Al = _A())
        : allocator(_Al) {_Tidy(); }
    basic_string(const _Myt& _X)
        : allocator(_X.allocator)
        {_Tidy(), assign(_X, 0, npos); }
    basic_string(const _Myt& _X, size_type _P, size_type _M,
        const _A& _Al = _A())
        : allocator(_Al) {_Tidy(), assign(_X, _P, _M); }
    basic_string(const _E *_S, size_type _N,
        const _A& _Al = _A())
        : allocator(_Al) {_Tidy(), assign(_S, _N); }
    basic_string(const _E *_S, const _A& _Al = _A())
        : allocator(_Al) {_Tidy(), assign(_S); }
    basic_string(size_type _N, _E _C, const _A& _Al = _A())
        : allocator(_Al) {_Tidy(), assign(_N, _C); }
    typedef const_iterator _It;
    basic_string(_It _F, _It _L, const _A& _Al = _A())
        : allocator(_Al) {_Tidy(); assign(_F, _L); }
    ~basic_string()
        {_Tidy(true); }
    typedef _Tr traits_type;
    typedef _A allocator_type;
    enum _Mref {_FROZEN = 255};
    static const size_type npos;
    _Myt& operator=(const _Myt& _X)
        {return (assign(_X)); }
    _Myt& operator=(const _E *_S)
        {return (assign(_S)); }
    _Myt& operator=(_E _C)
        {return (assign(1, _C)); }
    _Myt& operator+=(const _Myt& _X)
        {return (append(_X)); }
    _Myt& operator+=(const _E *_S)
        {return (append(_S)); }
    _Myt& operator+=(_E _C)
        {return (append(1, _C)); }
    _Myt& append(const _Myt& _X)
        {return (append(_X, 0, npos)); }
    _Myt& append(const _Myt& _X, size_type _P, size_type _M)
        {if (_X.size() < _P)
            _Xran();
        size_type _N = _X.size() - _P;
        if (_N < _M)
            _M = _N;
        if (npos - _Len <= _M)
            _Xlen();
        if (0 < _M && _Grow(_N = _Len + _M))
            {_Tr::copy(_Ptr + _Len, &_X.c_str()[_P], _M);
            _Eos(_N); }
        return (*this); }
    _Myt& append(const _E *_S, size_type _M)
        {if (npos - _Len <= _M)
            _Xlen();
        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
            {_Tr::copy(_Ptr + _Len, _S, _M);
            _Eos(_N); }
        return (*this); }
    _Myt& append(const _E *_S)
        {return (append(_S, _Tr::length(_S))); }
    _Myt& append(size_type _M, _E _C)
        {if (npos - _Len <= _M)
            _Xlen();
        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
            {_Tr::assign(_Ptr + _Len, _M, _C);
            _Eos(_N); }
        return (*this); }
    _Myt& append(_It _F, _It _L)
        {return (replace(end(), end(), _F, _L)); }
    _Myt& assign(const _Myt& _X)
        {return (assign(_X, 0, npos)); }
    _Myt& assign(const _Myt& _X, size_type _P, size_type _M)
        {if (_X.size() < _P)
            _Xran();
        size_type _N = _X.size() - _P;
        if (_M < _N)
            _N = _M;
        if (this == &_X)
            erase((size_type)(_P + _N)), erase(0, _P);
        else if (0 < _N && _N == _X.size()
            && _Refcnt(_X.c_str()) < _FROZEN - 1
            && allocator == _X.allocator)
            {_Tidy(true);
            _Ptr = (_E *)_X.c_str();
            _Len = _X.size();
            _Res = _X.capacity();
            ++_Refcnt(_Ptr); }
        else if (_Grow(_N, true))
            {_Tr::copy(_Ptr, &_X.c_str()[_P], _N);
            _Eos(_N); }
        return (*this); }
    _Myt& assign(const _E *_S, size_type _N)
        {if (_Grow(_N, true))
            {_Tr::copy(_Ptr, _S, _N);
            _Eos(_N); }
        return (*this); }
    _Myt& assign(const _E *_S)
        {return (assign(_S, _Tr::length(_S))); }
    _Myt& assign(size_type _N, _E _C)
        {if (_N == npos)
            _Xlen();
        if (_Grow(_N, true))
            {_Tr::assign(_Ptr, _N, _C);
            _Eos(_N); }
        return (*this); }
    _Myt& assign(_It _F, _It _L)
        {return (replace(begin(), end(), _F, _L)); }
    _Myt& insert(size_type _P0, const _Myt& _X)
        {return (insert(_P0, _X, 0, npos)); }
    _Myt& insert(size_type _P0, const _Myt& _X, size_type _P,
        size_type _M)
        {if (_Len < _P0 || _X.size() < _P)
            _Xran();
        size_type _N = _X.size() - _P;
        if (_N < _M)
            _M = _N;
        if (npos - _Len <= _M)
            _Xlen();
        if (0 < _M && _Grow(_N = _Len + _M))
            {_Tr::move(_Ptr + _P0 + _M, _Ptr + _P0, _Len - _P0);
            _Tr::copy(_Ptr + _P0, &_X.c_str()[_P], _M);
            _Eos(_N); }
        return (*this); }
    _Myt& insert(size_type _P0, const _E *_S, size_type _M)
        {if (_Len < _P0)
            _Xran();
        if (npos - _Len <= _M)
            _Xlen();
        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
            {_Tr::move(_Ptr + _P0 + _M, _Ptr + _P0, _Len - _P0);
            _Tr::copy(_Ptr + _P0, _S, _M);
            _Eos(_N); }
        return (*this); }
    _Myt& insert(size_type _P0, const _E *_S)
        {return (insert(_P0, _S, _Tr::length(_S))); }
    _Myt& insert(size_type _P0, size_type _M, _E _C)
        {if (_Len < _P0)
            _Xran();
        if (npos - _Len <= _M)
            _Xlen();
        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
            {_Tr::move(_Ptr + _P0 + _M, _Ptr + _P0, _Len - _P0);
            _Tr::assign(_Ptr + _P0, _M, _C);
            _Eos(_N); }
        return (*this); }
    iterator insert(iterator _P, _E _C)
        {size_type _P0 = _Pdif(_P, begin());
        insert(_P0, 1, _C);
        return (begin() + _P0); }
    void insert(iterator _P, size_type _M, _E _C)
        {size_type _P0 = _Pdif(_P, begin());
        insert(_P0, _M, _C); }
    void insert(iterator _P, _It _F, _It _L)
        {replace(_P, _P, _F, _L); }
    _Myt& erase(size_type _P0 = 0, size_type _M = npos)
        {if (_Len < _P0)
            _Xran();
        _Split();
        if (_Len - _P0 < _M)
            _M = _Len - _P0;
        if (0 < _M)
            {_Tr::move(_Ptr + _P0, _Ptr + _P0 + _M,
                _Len - _P0 - _M);
            size_type _N = _Len - _M;
            if (_Grow(_N))
                _Eos(_N); }
        return (*this); }
    iterator erase(iterator _P)
        {size_t _M = _Pdif(_P, begin());
        erase(_M, 1);
        return (_Psum(_Ptr, _M)); }
    iterator erase(iterator _F, iterator _L)
        {size_t _M = _Pdif(_F, begin());
        erase(_M, _Pdif(_L, _F));
        return (_Psum(_Ptr, _M)); }
    _Myt& replace(size_type _P0, size_type _N0, const _Myt& _X)
        {return (replace(_P0, _N0, _X, 0, npos)); }
    _Myt& replace(size_type _P0, size_type _N0, const _Myt& _X,
        size_type _P, size_type _M)
        {if (_Len < _P0 || _X.size() < _P)
            _Xran();
        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;
        size_type _N = _X.size() - _P;
        if (_N < _M)
            _M = _N;
        if (npos - _M <= _Len - _N0)
            _Xlen();
        _Split();
        size_type _Nm = _Len - _N0 - _P0;
        if (_M < _N0)
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
        if ((0 < _M || 0 < _N0) && _Grow(_N = _Len + _M - _N0))
            {if (_N0 < _M)
                _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
            _Tr::copy(_Ptr + _P0, &_X.c_str()[_P], _M);
            _Eos(_N); }
        return (*this); }
    _Myt& replace(size_type _P0, size_type _N0, const _E *_S,
        size_type _M)
        {if (_Len < _P0)
            _Xran();
        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;
        if (npos - _M <= _Len - _N0)
            _Xlen();
        _Split();
        size_type _Nm = _Len - _N0 - _P0;
        if (_M < _N0)
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
        size_type _N;
        if ((0 < _M || 0 < _N0) && _Grow(_N = _Len + _M - _N0))
            {if (_N0 < _M)
                _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
            _Tr::copy(_Ptr + _P0, _S, _M);
            _Eos(_N); }
        return (*this); }
    _Myt& replace(size_type _P0, size_type _N0, const _E *_S)
        {return (replace(_P0, _N0, _S, _Tr::length(_S))); }
    _Myt& replace(size_type _P0, size_type _N0,
        size_type _M, _E _C)
        {if (_Len < _P0)
            _Xran();
        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;
        if (npos - _M <= _Len - _N0)
            _Xlen();
        _Split();
        size_type _Nm = _Len - _N0 - _P0;
        if (_M < _N0)
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
        size_type _N;
        if ((0 < _M || 0 < _N0) && _Grow(_N = _Len + _M - _N0))
            {if (_N0 < _M)
                _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0,
                    _Nm);
            _Tr::assign(_Ptr + _P0, _M, _C);
            _Eos(_N); }
        return (*this); }
    _Myt& replace(iterator _F, iterator _L, const _Myt& _X)
        {return (replace(
            _Pdif(_F, begin()), _Pdif(_L, _F), _X)); }
    _Myt& replace(iterator _F, iterator _L, const _E *_S,
        size_type _M)
        {return (replace(
            _Pdif(_F, begin()), _Pdif(_L, _F), _S, _M)); }
    _Myt& replace(iterator _F, iterator _L, const _E *_S)
        {return (replace(
            _Pdif(_F, begin()), _Pdif(_L, _F), _S)); }
    _Myt& replace(iterator _F, iterator _L,	size_type _M, _E _C)
        {return (replace(
            _Pdif(_F, begin()), _Pdif(_L, _F), _M, _C)); }
    _Myt& replace(iterator _F1, iterator _L1,
        _It _F2, _It _L2)
        {size_type _P0 = _Pdif(_F1, begin());
        size_type _M = 0;
        _Distance(_F2, _L2, _M);
        replace(_P0, _Pdif(_L1, _F1), _M, _E(0));
        for (_F1 = begin() + _P0; 0 < _M; ++_F1, ++_F2, --_M)
            *_F1 = *_F2;
        return (*this); }
    iterator begin()
        {_Freeze();
        return (_Ptr); }
    const_iterator begin() const
        {return (_Ptr); }
    iterator end()
        {_Freeze();
        return ((iterator)_Psum(_Ptr, _Len)); }
    const_iterator end() const
        {return ((const_iterator)_Psum(_Ptr, _Len)); }
    reverse_iterator rbegin()
        {return (reverse_iterator(end())); }
    const_reverse_iterator rbegin() const
        {return (const_reverse_iterator(end())); }
    reverse_iterator rend()
        {return (reverse_iterator(begin())); }
    const_reverse_iterator rend() const
        {return (const_reverse_iterator(begin())); }
    reference at(size_type _P0)
        {if (_Len <= _P0)
            _Xran();
        _Freeze();
        return (_Ptr[_P0]); }
    const_reference at(size_type _P0) const
        {if (_Len <= _P0)
            _Xran();
        return (_Ptr[_P0]); }
    reference operator[](size_type _P0)
        {if (_Len < _P0 || _Ptr == 0)
            return ((reference)*_Nullstr());
        _Freeze();
        return (_Ptr[_P0]); }
    const_reference operator[](size_type _P0) const
        {if (_Ptr == 0)
            return (*_Nullstr());
        else
            return (_Ptr[_P0]); }
    const _E *c_str() const
        {return (_Ptr == 0 ? _Nullstr() : _Ptr); }
    const _E *data() const
        {return (c_str()); }
    size_type length() const
        {return (_Len); }
    size_type size() const
        {return (_Len); }
    size_type max_size() const
        {size_type _N = allocator.max_size();
        return (_N <= 2 ? 1 : _N - 2); }
    void resize(size_type _N, _E _C)
        {_N <= _Len ? erase(_N) : append(_N - _Len, _C); }
    void resize(size_type _N)
        {_N <= _Len ? erase(_N) : append(_N - _Len, _E(0)); }
    size_type capacity() const
        {return (_Res); }
    void reserve(size_type _N = 0)
        {if (_Res < _N)
            _Grow(_N); }
    bool empty() const
        {return (_Len == 0); }
    size_type copy(_E *_S, size_type _N, size_type _P0 = 0) const
        {if (_Len < _P0)
            _Xran();
        if (_Len - _P0 < _N)
            _N = _Len - _P0;
        if (0 < _N)
            _Tr::copy(_S, _Ptr + _P0, _N);
        return (_N); }
    void swap(_Myt& _X)
        {if (allocator == _X.allocator)
            {std::swap(_Ptr, _X._Ptr);
            std::swap(_Len, _X._Len);
            std::swap(_Res, _X._Res); }
        else
            {_Myt _Ts = *this; *this = _X, _X = _Ts; }}
    friend void swap(_Myt& _X, _Myt& _Y)
        {_X.swap(_Y); }
    size_type find(const _Myt& _X, size_type _P = 0) const
        {return (find(_X.c_str(), _P, _X.size())); }
    size_type find(const _E *_S, size_type _P,
        size_type _N) const
        {if (_N == 0 && _P <= _Len)
            return (_P);
        size_type _Nm;
        if (_P < _Len && _N <= (_Nm = _Len - _P))
            {const _E *_U, *_V;
            for (_Nm -= _N - 1, _V = _Ptr + _P;
                (_U = _Tr::find(_V, _Nm, *_S)) != 0;
                _Nm -= _U - _V + 1, _V = _U + 1)
                if (_Tr::compare(_U, _S, _N) == 0)
                    return (_U - _Ptr); }
        return (npos); }
    size_type find(const _E *_S, size_type _P = 0) const
        {return (find(_S, _P, _Tr::length(_S))); }
    size_type find(_E _C, size_type _P = 0) const
        {return (find((const _E *)&_C, _P, 1)); }
    size_type rfind(const _Myt& _X, size_type _P = npos) const
        {return (rfind(_X.c_str(), _P, _X.size())); }
    size_type rfind(const _E *_S, size_type _P,
        size_type _N) const
        {if (_N == 0)
            return (_P < _Len ? _P : _Len);
        if (_N <= _Len)
            for (const _E *_U = _Ptr +
                + (_P < _Len - _N ? _P : _Len - _N); ; --_U)
                if (_Tr::eq(*_U, *_S)
                    && _Tr::compare(_U, _S, _N) == 0)
                    return (_U - _Ptr);
                else if (_U == _Ptr)
                    break;
        return (npos); }
    size_type rfind(const _E *_S, size_type _P = npos) const
        {return (rfind(_S, _P, _Tr::length(_S))); }
    size_type rfind(_E _C, size_type _P = npos) const
        {return (rfind((const _E *)&_C, _P, 1)); }
    size_type find_first_of(const _Myt& _X,
        size_type _P = 0) const
        {return (find_first_of(_X.c_str(), _P, _X.size())); }
    size_type find_first_of(const _E *_S, size_type _P,
        size_type _N) const
        {if (0 < _N && _P < _Len)
            {const _E *const _V = _Ptr + _Len;
            for (const _E *_U = _Ptr + _P; _U < _V; ++_U)
                if (_Tr::find(_S, _N, *_U) != 0)
                    return (_U - _Ptr); }
        return (npos); }
    size_type find_first_of(const _E *_S, size_type _P = 0) const
        {return (find_first_of(_S, _P, _Tr::length(_S))); }
    size_type find_first_of(_E _C, size_type _P = 0) const
        {return (find((const _E *)&_C, _P, 1)); }
    size_type find_last_of(const _Myt& _X,
        size_type _P = npos) const
        {return (find_last_of(_X.c_str(), _P, _X.size())); }
    size_type find_last_of(const _E *_S, size_type _P,
        size_type _N) const
        {if (0 < _N && 0 < _Len)
            for (const _E *_U = _Ptr
                + (_P < _Len ? _P : _Len - 1); ; --_U)
                if (_Tr::find(_S, _N, *_U) != 0)
                    return (_U - _Ptr);
                else if (_U == _Ptr)
                    break;
        return (npos); }
    size_type find_last_of(const _E *_S,
        size_type _P = npos) const
        {return (find_last_of(_S, _P, _Tr::length(_S))); }
    size_type find_last_of(_E _C, size_type _P = npos) const
        {return (rfind((const _E *)&_C, _P, 1)); }
    size_type find_first_not_of(const _Myt& _X,
        size_type _P = 0) const
        {return (find_first_not_of(_X.c_str(), _P,
            _X.size())); }
    size_type find_first_not_of(const _E *_S, size_type _P,
        size_type _N) const
        {if (_P < _Len)
            {const _E *const _V = _Ptr + _Len;
            for (const _E *_U = _Ptr + _P; _U < _V; ++_U)
                if (_Tr::find(_S, _N, *_U) == 0)
                    return (_U - _Ptr); }
        return (npos); }
    size_type find_first_not_of(const _E *_S,
        size_type _P = 0) const
        {return (find_first_not_of(_S, _P, _Tr::length(_S))); }
    size_type find_first_not_of(_E _C, size_type _P = 0) const
        {return (find_first_not_of((const _E *)&_C, _P, 1)); }
    size_type find_last_not_of(const _Myt& _X,
        size_type _P = npos) const
        {return (find_last_not_of(_X.c_str(), _P, _X.size())); }
    size_type find_last_not_of(const _E *_S, size_type _P,
         size_type _N) const
        {if (0 < _Len)
            for (const _E *_U = _Ptr
                + (_P < _Len ? _P : _Len - 1); ; --_U)
                if (_Tr::find(_S, _N, *_U) == 0)
                    return (_U - _Ptr);
                else if (_U == _Ptr)
                    break;
        return (npos); }
    size_type find_last_not_of(const _E *_S,
        size_type _P = npos) const
        {return (find_last_not_of(_S, _P, _Tr::length(_S))); }
    size_type find_last_not_of(_E _C, size_type _P = npos) const
        {return (find_last_not_of((const _E *)&_C, _P, 1)); }
    _Myt substr(size_type _P = 0, size_type _M = npos) const
        {return (_Myt(*this, _P, _M)); }
    int compare(const _Myt& _X) const
        {return (compare(0, _Len, _X.c_str(), _X.size())); }
    int compare(size_type _P0, size_type _N0,
        const _Myt& _X) const
        {return (compare(_P0, _N0, _X, 0, npos)); }
    int compare(size_type _P0, size_type _N0, const _Myt& _X,
        size_type _P, size_type _M) const
        {if (_X.size() < _P)
            _Xran();
        if (_X._Len - _P < _M)
            _M = _X._Len - _P;
        return (compare(_P0, _N0, _X.c_str() + _P, _M)); }
    int compare(const _E *_S) const
        {return (compare(0, _Len, _S, _Tr::length(_S))); }
    int compare(size_type _P0, size_type _N0, const _E *_S) const
        {return (compare(_P0, _N0, _S, _Tr::length(_S))); }
    int compare(size_type _P0, size_type _N0, const _E *_S,
        size_type _M) const
        {if (_Len < _P0)
            _Xran();
        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;
        size_type _Ans = _Tr::compare(_Psum(_Ptr, _P0), _S,
            _N0 < _M ? _N0 : _M);
        return (_Ans != 0 ? _Ans : _N0 < _M ? -1
            : _N0 == _M ? 0 : +1); }
    _A get_allocator() const
        {return (allocator); }
protected:
    _A allocator;
private:
    enum {_MIN_SIZE = sizeof (_E) <= 32 ? 31 : 7};
    void _Copy(size_type _N)
        {size_type _Ns = _N | _MIN_SIZE;
        if (max_size() < _Ns)
            _Ns = _N;
        _E *_S;
        _TRY_BEGIN
            _S = allocator.allocate(_Ns + 2, (void *)0);
        _CATCH_ALL
            _Ns = _N;
            _S = allocator.allocate(_Ns + 2, (void *)0);
        _CATCH_END
        if (0 < _Len)
            _Tr::copy(_S + 1, _Ptr,_Len>_Ns?_Ns:_Len);
        size_type _Olen = _Len;
        _Tidy(true);
        _Ptr = _S + 1;
        _Refcnt(_Ptr) = 0;
        _Res = _Ns;
        _Eos(_Olen>_Ns?_Ns:_Olen); }
    void _Eos(size_type _N)
        {_Tr::assign(_Ptr[_Len = _N], _E(0)); }
    void _Freeze()
        {if (_Ptr != 0
            && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
            _Grow(_Len);
        if (_Ptr != 0)
            _Refcnt(_Ptr) = _FROZEN; }
    bool _Grow(size_type _N, bool _Trim = false)
        {if (max_size() < _N)
            _Xlen();
        if (_Ptr != 0
            && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
            if (_N == 0)
                {--_Refcnt(_Ptr), _Tidy();
                return (false); }
            else
                {_Copy(_N);
                return (true); }
        if (_N == 0)
            {if (_Trim)
                _Tidy(true);
            else if (_Ptr != 0)
                _Eos(0);
            return (false); }
        else
            {if (_Trim && (_MIN_SIZE < _Res || _Res < _N))
                {_Tidy(true);
                _Copy(_N); }
            else if (!_Trim && _Res < _N)
                _Copy(_N);
            return (true); }}
    static const _E * __cdecl _Nullstr()
        {static const _E _C = _E(0);
        return (&_C); }
    static size_type _Pdif(const_pointer _P2, const_pointer _P1)
        {return (_P2 == 0 ? 0 : _P2 - _P1); }
    static const_pointer _Psum(const_pointer _P, size_type _N)
        {return (_P == 0 ? 0 : _P + _N); }
    static pointer _Psum(pointer _P, size_type _N)
        {return (_P == 0 ? 0 : _P + _N); }
    unsigned char& _Refcnt(const _E *_U)
        {return (((unsigned char *)_U)[-1]); }
    void _Split()
        {if (_Ptr != 0 && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
            {_E *_Temp = _Ptr;
            _Tidy(true);
            assign(_Temp); }}
    void _Tidy(bool _Built = false)
        {if (!_Built || _Ptr == 0)
            ;
        else if (_Refcnt(_Ptr) == 0 || _Refcnt(_Ptr) == _FROZEN)
            allocator.deallocate(_Ptr - 1, _Res + 2);
        else
            --_Refcnt(_Ptr);
        _Ptr = 0, _Len = 0, _Res = 0; }
    _E *_Ptr;
    size_type _Len, _Res;
    };
template<class _E, class _Tr, class _A>
    const basic_string<_E, _Tr, _A>::size_type
        basic_string<_E, _Tr, _A>::npos = -1;

extern template class _CRTIMP basic_string<char, char_traits<char>, allocator<char> >;
extern template class _CRTIMP basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >;

typedef basic_string<char, char_traits<char>, allocator<char> >
    string;

typedef basic_string<wchar_t, char_traits<wchar_t>,
    allocator<wchar_t> > wstring;

       // basic_string TEMPLATE OPERATORS
template<class _E, class _Tr, class _A> inline
    basic_string<_E, _Tr, _A> __cdecl operator+(
        const basic_string<_E, _Tr, _A>& _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (basic_string<_E, _Tr, _A>(_L) += _R); }

template<class _E, class _Tr, class _A> inline
    basic_string<_E, _Tr, _A> __cdecl operator+(const _E *_L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (basic_string<_E, _Tr, _A>(_L) += _R); }

template<class _E, class _Tr, class _A> inline
    basic_string<_E, _Tr, _A> __cdecl operator+(
        const _E _L, const basic_string<_E, _Tr, _A>& _R)
    {return (basic_string<_E, _Tr, _A>(1, _L) += _R); }

template<class _E, class _Tr, class _A> inline
    basic_string<_E, _Tr, _A> __cdecl operator+(
        const basic_string<_E, _Tr, _A>& _L,
        const _E *_R)
    {return (basic_string<_E, _Tr, _A>(_L) += _R); }

template<class _E, class _Tr, class _A> inline
    basic_string<_E, _Tr, _A> __cdecl operator+(
        const basic_string<_E, _Tr, _A>& _L, const _E _R)
    {return (basic_string<_E, _Tr, _A>(_L) += _R); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator==(const basic_string<_E, _Tr, _A>& _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (_L.compare(_R) == 0); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator==(const _E * _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (_R.compare(_L) == 0); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator==(const basic_string<_E, _Tr, _A>& _L,
        const _E *_R)
    {return (_L.compare(_R) == 0); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator!=(const basic_string<_E, _Tr, _A>& _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (!(_L == _R)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator!=(const _E *_L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (!(_L == _R)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator!=(const basic_string<_E, _Tr, _A>& _L,
        const _E *_R)
    {return (!(_L == _R)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator<(const basic_string<_E, _Tr, _A>& _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (_L.compare(_R) < 0); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator<(const _E * _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (_R.compare(_L) > 0); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator<(const basic_string<_E, _Tr, _A>& _L,
        const _E *_R)
    {return (_L.compare(_R) < 0); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator>(const basic_string<_E, _Tr, _A>& _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (_R < _L); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator>(const _E * _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (_R < _L); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator>(const basic_string<_E, _Tr, _A>& _L,
        const _E *_R)
    {return (_R < _L); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator<=(const basic_string<_E, _Tr, _A>& _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (!(_R < _L)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator<=(const _E * _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (!(_R < _L)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator<=(const basic_string<_E, _Tr, _A>& _L,
        const _E *_R)
    {return (!(_R < _L)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator>=(const basic_string<_E, _Tr, _A>& _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (!(_L < _R)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator>=(const _E * _L,
        const basic_string<_E, _Tr, _A>& _R)
    {return (!(_L < _R)); }

template<class _E, class _Tr, class _A> inline
    bool __cdecl operator>=(const basic_string<_E, _Tr, _A>& _L,
        const _E *_R)
    {return (!(_L < _R)); }
        // basic_string INSERTERS AND EXTRACTORS

template<class _E, class _Tr, class _A> inline
    basic_istream<_E, _Tr>& __cdecl operator>>(
        basic_istream<_E, _Tr>& _I,
        basic_string<_E, _Tr, _A>& _X)
    {typedef ctype<_E> _Ctype;
    typedef basic_istream<_E, _Tr> _Myis;
    ios_base::iostate _St = ios_base::goodbit;
    bool _Chg = false;
    _X.erase();
    const _Myis::sentry _Ok(_I);
    if (_Ok)
        {const _Ctype& _Fac = _USE(_I.getloc(), _Ctype);
        _TRY_IO_BEGIN
        _A::size_type _N = 0 < _I.width()
            && _I.width() < _X.max_size()
                ? _I.width() : _X.max_size();
        _Tr::int_type _C = _I.rdbuf()->sgetc();
        for (; 0 < --_N; _C = _I.rdbuf()->snextc())
            if(_Tr::eq_int_type(_Tr::eof(), _C))
                {_St |= ios_base::eofbit;
                break; }
            else if (_Fac.is(_Ctype::space,
                _Tr::to_char_type(_C)))
                break;
            else
                {_X.append(1, _Tr::to_char_type(_C));
                _Chg = true; }
        _CATCH_IO_(_I); }
    _I.width(0);
    if (!_Chg)
        _St |= ios_base::failbit;
    _I.setstate(_St);
    return (_I); }

template<class _E, class _Tr, class _A> inline
    basic_istream<_E, _Tr>& __cdecl getline(basic_istream<_E, _Tr>& _I,
        basic_string<_E, _Tr, _A>& _X)
    {return (getline(_I, _X, _I.widen(&apos;\n&apos;))); }

template<class _E, class _Tr, class _A> inline
    basic_istream<_E, _Tr>& __cdecl getline(basic_istream<_E, _Tr>& _I,
        basic_string<_E, _Tr, _A>& _X, const _E _D)
    {typedef basic_istream<_E, _Tr> _Myis;
    ios_base::iostate _St = ios_base::goodbit;
    bool _Chg = false;
    _X.erase();
    const _Myis::sentry _Ok(_I, true);
    if (_Ok)
        {_TRY_IO_BEGIN
        _Tr::int_type _C = _I.rdbuf()->sgetc();
        for (; ; _C = _I.rdbuf()->snextc())
            if (_Tr::eq_int_type(_Tr::eof(), _C))
                {_St |= ios_base::eofbit;
                break; }
            else if (_Tr::eq((_E)_C, _D))
                {_Chg = true;
                _I.rdbuf()->snextc();
                break; }
            else if (_X.max_size() <= _X.size())
                {_St |= ios_base::failbit;
                break; }
            else
                _X += _Tr::to_char_type(_C), _Chg = true;
        _CATCH_IO_(_I); }
    if (!_Chg)
        _St |= ios_base::failbit;
    _I.setstate(_St);
    return (_I); }
template<class _E, class _Tr, class _A> inline
    basic_ostream<_E, _Tr>& __cdecl operator<<(
        basic_ostream<_E, _Tr>& _O,
        const basic_string<_E, _Tr, _A>& _X)
    {
    _O << _X.c_str();
    return (_O); }

extern template class _CRTIMP
    basic_string<char, char_traits<char>, allocator<char> > __cdecl operator+(
        const basic_string<char, char_traits<char>, allocator<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template class _CRTIMP
    basic_string<char, char_traits<char>, allocator<char> > __cdecl operator+(
        const char *, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template class _CRTIMP
    basic_string<char, char_traits<char>, allocator<char> > __cdecl operator+(
        const char, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template class _CRTIMP
    basic_string<char, char_traits<char>, allocator<char> > __cdecl operator+(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char *);

extern template class _CRTIMP
    basic_string<char, char_traits<char>, allocator<char> > __cdecl operator+(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char);

extern template _CRTIMP bool __cdecl operator==(
        const basic_string<char, char_traits<char>, allocator<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator==(
        const char *, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator==(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char *);

extern template _CRTIMP bool __cdecl operator!=(
        const basic_string<char, char_traits<char>, allocator<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator!=(
        const char *, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator!=(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char *);

extern template _CRTIMP bool __cdecl operator<(
        const basic_string<char, char_traits<char>, allocator<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator<(
        const char *, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator<(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char *);

extern template _CRTIMP bool __cdecl operator>(
        const basic_string<char, char_traits<char>, allocator<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator>(
        const char *, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator>(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char *);

extern template _CRTIMP bool __cdecl operator<=(
        const basic_string<char, char_traits<char>, allocator<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator<=(
        const char *, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator<=(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char *);

extern template _CRTIMP bool __cdecl operator>=(
        const basic_string<char, char_traits<char>, allocator<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator>=(
        const char *, const basic_string<char, char_traits<char>, allocator<char> >&);

extern template _CRTIMP bool __cdecl operator>=(
        const basic_string<char, char_traits<char>, allocator<char> >&, const char *);

extern template class _CRTIMP
    basic_istream<char, char_traits<char> >& __cdecl operator>>(
        basic_istream<char, char_traits<char> >&,
        basic_string<char, char_traits<char>, allocator<char> >&);

extern template class _CRTIMP
    basic_istream<char, char_traits<char> >& __cdecl getline(
        basic_istream<char, char_traits<char> >&,
        basic_string<char, char_traits<char>, allocator<char> >&);

extern template class _CRTIMP
    basic_istream<char, char_traits<char> >& __cdecl getline(
        basic_istream<char, char_traits<char> >&,
        basic_string<char, char_traits<char>, allocator<char> >&, const char);

extern template class _CRTIMP
    basic_ostream<char, char_traits<char> >& __cdecl operator<<(
        basic_ostream<char, char_traits<char> >&,
        const basic_string<char, char_traits<char>, allocator<char> >&);

extern template class _CRTIMP
    basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > __cdecl operator+(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template class _CRTIMP
    basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > __cdecl operator+(
        const wchar_t *, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template class _CRTIMP
    basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > __cdecl operator+(
        const wchar_t, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template class _CRTIMP
    basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > __cdecl operator+(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t *);

extern template class _CRTIMP
    basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > __cdecl operator+(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t);

extern template _CRTIMP bool __cdecl operator==(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator==(
        const wchar_t *, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator==(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t *);

extern template _CRTIMP bool __cdecl operator!=(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator!=(
        const wchar_t *, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator!=(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t *);

extern template _CRTIMP bool __cdecl operator<(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator<(
        const wchar_t *, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator<(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t *);

extern template _CRTIMP bool __cdecl operator>(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator>(
        const wchar_t *, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator>(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t *);

extern template _CRTIMP bool __cdecl operator<=(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator<=(
        const wchar_t *, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator<=(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t *);

extern template _CRTIMP bool __cdecl operator>=(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator>=(
        const wchar_t *, const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template _CRTIMP bool __cdecl operator>=(
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t *);

extern template class _CRTIMP
    basic_istream<wchar_t, char_traits<wchar_t> >& __cdecl operator>>(
        basic_istream<wchar_t, char_traits<wchar_t> >&,
        basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template class _CRTIMP
    basic_istream<wchar_t, char_traits<wchar_t> >& __cdecl getline(
        basic_istream<wchar_t, char_traits<wchar_t> >&,
        basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

extern template class _CRTIMP
    basic_istream<wchar_t, char_traits<wchar_t> >& __cdecl getline(
        basic_istream<wchar_t, char_traits<wchar_t> >&,
        basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&, const wchar_t);

extern template class _CRTIMP
    basic_ostream<wchar_t, char_traits<wchar_t> >& __cdecl operator<<(
        basic_ostream<wchar_t, char_traits<wchar_t> >&,
        const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);

template<class _E>
        struct char_traits {
        typedef _E char_type;
        typedef _E int_type;
        typedef streampos pos_type;
        typedef streamoff off_type;
        typedef mbstate_t state_type;
        static void __cdecl assign(_E& _X, const _E& _Y)
                {_X = _Y; }
        static bool __cdecl eq(const _E& _X, const _E& _Y)
                {return (_X == _Y); }
        static bool __cdecl lt(const _E& _X, const _E& _Y)
                {return (_X < _Y); }
        static int __cdecl compare(const _E *_U, const _E *_V, size_t _N)
                {for (size_t _I = 0; _I < _N; ++_I, ++_U, ++_V)
                        if (!eq(*_U, *_V))
                                return (lt(*_U, *_V) ? -1 : +1);
                return (0); }
        static size_t __cdecl length(const _E *_U)
                {size_t _N;
                for (_N = 0; !eq(*_U, _E(0)); ++_U)
                        ++_N;
                return (_N); }
        static _E * __cdecl copy(_E *_U, const _E *_V, size_t _N)
                {_E *_S = _U;
                for (; 0 < _N; --_N, ++_U, ++_V)
                        assign(*_U, *_V);
                return (_S); }
        static const _E * __cdecl find(const _E *_U, size_t _N,
                const _E& _C)
                {for (; 0 < _N; --_N, ++_U)
                        if (eq(*_U, _C))
                                return (_U);
                return (0); }
        static _E * __cdecl move(_E *_U, const _E *_V, size_t _N)
                {_E *_Ans = _U;
                if (_V < _U && _U < _V + _N)
                        for (_U += _N, _V += _N; 0 < _N; --_N)
                                assign(*--_U, *--_V);
                else
                        for (; 0 < _N; --_N, ++_U, ++_V)
                                assign(*_U, *_V);
                return (_Ans); }
        static _E * __cdecl assign(_E *_U, size_t _N, const _E& _C)
                {_E *_Ans = _U;
                for (; 0 < _N; --_N, ++_U)
                        assign(*_U, _C);
                return (_Ans); }
        static _E __cdecl to_char_type(const int_type& _C)
                {return ((_E)_C); }
        static int_type __cdecl to_int_type(const _E& _C)
                {return ((int_type)_C); }
        static bool __cdecl eq_int_type(const int_type& _X,
                const int_type& _Y)
                {return (_X == _Y); }
        static int_type __cdecl eof()
                {return (EOF); }
        static int_type __cdecl not_eof(const int_type& _C)
                {return (_C != eof() ? _C : !eof()); }
        };

                // STRUCT char_traits<wchar_t>
template<> struct _CRTIMP char_traits<wchar_t> {
        typedef wchar_t _E;
        typedef _E char_type;   // for overloads
        typedef wint_t int_type;
        typedef streampos pos_type;
        typedef streamoff off_type;
        typedef mbstate_t state_type;
        static void __cdecl assign(_E& _X, const _E& _Y)
                {_X = _Y; }
        static bool __cdecl eq(const _E& _X, const _E& _Y)
                {return (_X == _Y); }
        static bool __cdecl lt(const _E& _X, const _E& _Y)
                {return (_X < _Y); }
        static int __cdecl compare(const _E *_U, const _E *_V, size_t _N)
                {return (wmemcmp(_U, _V, _N)); }
        static size_t __cdecl length(const _E *_U)
                {return (wcslen(_U)); }
        static _E *__cdecl copy(_E *_U, const _E *_V, size_t _N)
                {return (wmemcpy(_U, _V, _N)); }
        static const _E * __cdecl find(const _E *_U, size_t _N,
                const _E& _C)
                {return ((const _E *)wmemchr(_U, _C, _N)); }
        static _E * __cdecl move(_E *_U, const _E *_V, size_t _N)
                {return (wmemmove(_U, _V, _N)); }
        static _E * __cdecl assign(_E *_U, size_t _N, const _E& _C)
                {return (wmemset(_U, _C, _N)); }
        static _E __cdecl to_char_type(const int_type& _C)
                {return ((_E)_C); }
        static int_type __cdecl to_int_type(const _E& _C)
                {return ((int_type)_C); }
        static bool __cdecl eq_int_type(const int_type& _X,
                const int_type& _Y)
                {return (_X == _Y); }
        static int_type __cdecl eof()
                {return (WEOF); }
        static int_type __cdecl not_eof(const int_type& _C)
                {return (_C != eof() ? _C : !eof()); }
        };

                // STRUCT char_traits<char> (FROM <string>)
template<> struct _CRTIMP char_traits<char> {
        typedef char _E;
        typedef _E char_type;
        typedef int int_type;
        typedef streampos pos_type;
        typedef streamoff off_type;
        typedef mbstate_t state_type;
        static void __cdecl assign(_E& _X, const _E& _Y)
                {_X = _Y; }
        static bool __cdecl eq(const _E& _X, const _E& _Y)
                {return (_X == _Y); }
        static bool __cdecl lt(const _E& _X, const _E& _Y)
                {return (_X < _Y); }
        static int __cdecl compare(const _E *_U, const _E *_V, size_t _N)
                {return (memcmp(_U, _V, _N)); }
        static size_t __cdecl length(const _E *_U)
                {return (strlen(_U)); }
        static _E * __cdecl copy(_E *_U, const _E *_V, size_t _N)
                {return ((_E *)memcpy(_U, _V, _N)); }
        static const _E * __cdecl find(const _E *_U, size_t _N,
                const _E& _C)
                {return ((const _E *)memchr(_U, _C, _N)); }
        static _E * __cdecl move(_E *_U, const _E *_V, size_t _N)
                {return ((_E *)memmove(_U, _V, _N)); }
        static _E * __cdecl assign(_E *_U, size_t _N, const _E& _C)
                {return ((_E *)memset(_U, _C, _N)); }
        static _E __cdecl to_char_type(const int_type& _C)
                {return ((_E)_C); }
        static int_type __cdecl to_int_type(const _E& _C)
                {return ((int_type)((unsigned char)_C)); }
        static bool __cdecl eq_int_type(const int_type& _X,
                const int_type& _Y)
                {return (_X == _Y); }
        static int_type __cdecl eof()
                {return (EOF); }
        static int_type __cdecl not_eof(const int_type& _C)
                {return (_C != eof() ? _C : !eof()); }
        };

  Java java.lang.String

public final class java.lang.String extend java.lang.Object
{
    public	String();
    public	String(byte ascii[], int hibyte);
    public	String(byte ascii[], int hibyte, int offset, int count);
    public	String(char value[]);
    public	String(char value[], int offset, int count);
    public  String(String value);
    public  String(StringBuilder buffer);

    public	char	charAt(int index);
    public	int	compareTo(String anotherString);
    public	String	concat(String str);
    public	static	String	copyValueOf(char data[]);
    public	static	String	copyValueOf(char data[], int offset, int count);
    public	boolean	endsWith(String suffix);
    public	boolean equals(Object anObject);
    public	boolean equalsIgnoreCase(String anotherString);

    public	void	getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin);
    public  void	getChars(int srcBegin, int srcEnd, char dst[], int dstBegin);

    public  int	hashcode();
    public	int	indexOf(int char);
    public	int	indexOf(int ch, int fromIndex);
    public	int	indexOf(String str);
    public	int	indexOf(String str, int fromIndex);
    public	String	intern();		// strdup

    public	int	lastIndexOf(int ch);
    public	int	lastIndexOf(int ch, int fromIndex);
    public	int	lastIndexOf(String str);
    public	int	lastIndexOf(String str, int fromIndex);

    public	int	length();

    public	boolean	regionMatches(boolean ignoreCase, int toOffset,
                      String other, int offset, int len);
    public	boolean	regionMatches(int toOffset, String other, int offset, int len);

    public	String	replace(char oldChar, char NewChar);
    public	boolean	startsWith(String prefix);
    public	boolean	startsWith(String prefix, int toOffset);

    public	String	substring(int beginIndex);
    public	String  substring(int beginIndex, int endIndex);
    public	char[]	toCharArray();
    public	String	toLowerCase();
    public	String	toString();
    public	String	toUpperCase();
    public	String	trim();

    public	static	String	valueOf(boolean b);
    public	static	String	valueOf(char c);
    public	static	String	valueOf(char data[]);
    public	static	String	valueOf(char data[], int offset, int count);
    public	static	String	valueOf(double d);
    public	static	String	valueOf(float f);
    public	static	String	valueOf(int  i);
    public	static	String	valueOf(long l);
    public	static	String	valueOf(Object Obj);
}

  C# System.String

Обратите внимание на расшепление классов:
    System.String 		- неизменяемая строка
        (исползуют для передачи в интерфейсы)

    System.StringBuileder   - изменяемая строка
        (используют для посторения неизменяемой строки)

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

public sealed class System.String: IComparable, ICloneable, IConvertable,
                   IComparable<String>, IEnumerable<char>,
                   IEnumerable, IEnumerable<String>
{
// Constructors:
public			String(char* value);
public			String(char[] value);
public			String(SByte* value);
public			String(char c, int count);
public			String(char* value, int startIndex, int length);
public			String(char[] value, int startIndex, int length);
public			String(SByte* value, int startIndex, int length);
public			Strign(SByte* value, int startIndex, int length, Encoding enc);

// Methods:
public		string	Clone();
public	static	int	Compare(string s1, string s2);
public	static	int	Compare(string s1, string s2, bool ignoreCase);
public	static	int	Compare(string s1, string s2, StringComparison comparisonType);
public	static	int	Compare(string s1, string s2, bool ignoreCase, CultureInfo culture);
public	static	int	Compare(string s1, int index1, string s2, int index2, int len);
public	static	int	Compare(string s1, int index1, string s2, int index2, int len, bool ignoreCase);
public	static	int	Compare(string s1, int index1, string s2, int index2, int len, StringComparison comparisonType);
public	static	int	Compare(string s1, int index1, string s2, int index2, int len, bool ignoreCase, CultureInfo culture);
public	static	int	CompareOrdinal(string s1, string s2);
public	static	int	CompareOrdinal(string s1, int index1, string s2, int index2, int len);
public		int	CompareTo(Object value);
public		int	CompareTo(String s);
public	static	string	Concat(Object o);
public	static	string	Concat(Object[] args);
public	static	string	Concat(string[] values);
public	static	string	Concat(Object o1, Object o2);
public	static	string	Concat(string s1, string s2);
public	static	string	Concat(Object o1, Object o2, Object o3);
public	static	string	Concat(string s1, string s2, string s3);
public	static	string	Concat(Object o1, Object o2, Object o3, Object o4);
public	static	string	Concat(string s1, string s2, string s3, string s4);
public	        bool	Contains(string value);
public	static	string	Copy(string src);
public		void	CopyTo(int sourceIndex, char[] dest, int destIndex, int count);
public		bool	EndsWith(string value);
public		bool	EndsWith(string value, StringComparison comparisonType);
public		bool	EndsWith(string value, bool ignoreCase, CultureInfo culture);
public		bool	Equals(Object o);
public		bool	Equals(string value);
public	static	bool	Equals(string s1, string s2);
public		bool	Equals(string value, StringComparison comparisonType);
public	static	bool	Equals(string s1, string s2, StringComparison comparisonTYpe);
public		CharEnumerator  GetEnumerator();
public		int	GetHashCode();
public		int	IndexOf(char value);
public		int	IndexOf(string value);
public		int	IndexOf(char value, int startIndex);
public		int	IndexOf(string value, int startIndex);
public		int	IndexOf(string value, StringComparison comparisonType);
public		int	IndexOf(string value, int startIndex, StringComparison comparisonType);
public		int	IndexOf(char value, int startIndex, int count);
public		int	IndexOf(string value, int startIndex, int count);
public		int	IndexOf(string value, int startIndex, int count, StringComparison comparisonType);
public		int	IndexOfAny(char[] anyof);
public		int	IndexOfAny(char[] anyof, int startIndex);
public		int	IndexOfAny(char[] anyof, int startIndex, int count);
public		string	Insert(int startIndex, string value);
public		bool	IsNormalized();		// UNICODE NORMAL FORM C
public		bool	IsNormalized(NormalizationForm normalizationForm);
public	static	bool	IsNullOrEmpty(string value);
public	static	string	Join(string separator, string[] value);
public	static	string	Join(string separator, string[] value, int startIndex, int count);
public		int	LastIndexOf(char value);
public		int	LastIndexOf(string value);
public		int	LastIndexOf(char value, int startIndex);
public		int	LastIndexOf(string value, int startIndex);
public		int	LastIndexOf(string value, StringComparison comparisonType);
public		int	LastIndexOf(string value, int startIndex, StringComparison comparisonType);
public		int	LastIndexOf(char value, int startIndex, int count);
public		int	LastIndexOf(string value, int startIndex, int count);
public		int	LastIndexOf(string value, int startIndex, int count, StringComparison comparisonType);
public		int	LastIndexOfAny(char[] anyof);
public		int	LastIndexOfAny(char[] anyof, int startIndex);
public		int	LastIndexOfAny(char[] anyof, int startIndex, int count);
public		string	Normalize();
public		string	Normalize(NormalizationForm normalizationForm);
public		string	PadLeft(int totalWidth);
public		string	PadLeft(int totalWidth, char padchar);
public		string	PadRight(int totalWidth);
public		string	PadRight(int totalWidth, char padchar);
public		string	Remove(int startIndex);
public		string	Remove(int startIndex, int count);
public		string	Replace(char oldchar, char newchar);
public		string	Replace(string oldValue, string newValue);
public		string[] Split(char[] separator);
public		string[] Split(char[] separator, int count);
public		string[] Split(char[] separator, StringSplitOptions options);
public		string[] Split(string[] separator, StringSplitOptions options);
public		string[] Split(char[] separator, int count, StringSplitOptions options);
public		string[] Split(string[] separator, int count, StringSplitOptions options);
public		bool	StartsWith(string value);
public		bool	StartsWith(string value, StringComparison comparisonType);
public		bool	StartsWith(string value, bool ignoreCase, CultureInfo culture);
public		string	Substring(int startIndex);
public		string	Substring(int startIndex, int length);
public		char[]	ToCharArray();
public		char[]	ToCharArray(int startIndex, int length);
public		string	ToLower();
public		string	ToLower(CultureInfo culture);
public		string	ToLowerInvariant();
public		string  ToString();
public		string	ToUpper();
public		string	ToUpper(CultureInfo culture);
public		string	ToUpperInvariant();
public		string	Trim();
public		string  Trim(char[] trimChars);
public		string	TrimEnd(char[] trimChars);
public		string	TrimStart(char[] trimChars);

public	static	string	Format(string format, Object o);
public	static	string	Format(string format, Object o1, Object o2);
public	static	string	Format(string format, Object o1, Object o2, Object o3);
public	static	string	Format(string format, Object[] objs);
public	static	string	Format(IFormatProvider provider, string format, Object[] objs);

// Operators:
public	static	bool	operator==(string s1, string s2);
public	static	bool	operator!=(string s1, string s2);

// Properties:
public		char	Chars[int index] { get; }
property	int	Length  { get; }

// Static fields:
public	static	readonly  string Empty;
}

public sealed class StringBuilder : ISerializable
{
public			StringBuilder();
public			StringBuilder(int capacity);
public			StringBuilder(string value);
public			StringBuilder(int initCapacity, int maxCapacity);
public			StringBuilder(string value, int maxCapacity);
public			StringBuilder(string value, int startIndex, int length, int maxCapacity);

public		StringBuilder Append(bool value);
public		StringBuilder Append(byte value);
public		StringBuilder Append(char value);
public		StringBuilder Append(char[] value);
public		StringBuilder Append(double value);
public		StringBuilder Append(short value);
public		StringBuilder Append(int value);
public		StringBuilder Append(long value);
public		StringBuilder Append(Object value);
public		StringBuilder Append(sbyte value);
public		StringBuilder Append(float value);
public		StringBuilder Append(ushort value);
public		StringBuilder Append(uint value);
public		StringBuilder Append(ulong value);
public		StringBuilder Append(string value);
public		StringBuilder Append(char value, int repeatCount);
public		StringBuilder Append(char[] value, int startIndex, int length);
public		StringBuilder Append(string value, int startIndex, int length);
public		StringBuilder AppendFormat(string format, Object o);
public		StringBuilder AppendFormat(string format, Object o1, Object o2);
public		StringBuilder AppendFormat(string format, Object o1, Object o2, Object o3);
public		StringBuilder AppendFormat(string format, Object[] objs);
public		StringBuilder AppendFormat(IFormatProvider provider, string format, Object[] objs);
public		StringBuilder AppendLine();		// add CR,LF
public		StringBuilder AppendLine(string s);	// add s, then add CR,LF
public		void	CopyTo(int srcIndex, char[] dest, int dstIndex, int count);
public		int	EnsureCapacity(int capacity);
public		bool	Equals(Object o);
public		bool	Equals(StringBuilder sb);
public		int	GetHashCode();
public		StringBuilder Insert(int index, bool value);
public		StringBuilder Insert(int index, byte value);
public		StringBuilder Insert(int index, char value);
public		StringBuilder Insert(int index, char[] value);
public		StringBuilder Insert(int index, double value);
public		StringBuilder Insert(int index, short value);
public		StringBuilder Insert(int index, int value);
public		StringBuilder Insert(int index, long value);
public		StringBuilder Insert(int index, Object value);
public		StringBuilder Insert(int index, sbyte value);
public		StringBuilder Insert(int index, float value);
public		StringBuilder Insert(int index, ushort value);
public		StringBuilder Insert(int index, uint value);
public		StringBuilder Insert(int index, ulong value);
public		StringBuilder Insert(int index, string value);
public		StringBuilder Insert(int index, char value, int repeatCount);
public		StringBuilder Insert(int index, char[] value, int startIndex, int length);
public		StringBuilder Insert(int index, string value, int startIndex, int length);
public		StringBuilder Remove(int startIndex, int length);
public		StringBuilder Replace(char oldval, char newval);
public		StringBuilder Replace(string oldval, string newval);
public		StringBuilder Replace(char oldval, char newval, int startIndex, int length);
public		StringBuilder Replace(string oldval, string newval, int startIndex, int length);
public		string	ToString();
public		string	ToString(int startIndex, int length);

// properties:
public		int	Capacity 	 { get; set; }
public		char	Chars[int index] { get; set; }
public		int	Length		 { get; set; }
public		int	MaxCapacity	 { get;      }
}

public enum StringComparison
{
    CurrentCulture,
    CurrentCultureIgnoreCase,
    InvariantCulture,
    InvariantCultureIgnoreCase,
    Ordinal,
    OrdinalIgnoreCase
}

  Delphi RTL

{AnsiString}

function AnsiLowerCase(const S:string):string;
function AnsiUpperCase(const s:string):string;
function Concat(s1 [,s2, ..., sN] : string):string;
function Copy(st:string; index, count:integer):string;
procedure Delete(st:string; index,count:integer);
procedure Insert(st:string; st,index:integer);
function  Length(st:string):integer;
function  LowerCase(const s:string):string;
procedure OleStrToStrVar(source:PWideChar; var dest:string);
function  Pos(subst, st:string):integer;
procedure SetLength(st:string; newLength:integer);
function  StringOfChar(ch:char; count:integer):string;
function  StringToOleChar(const source:string):PWideChar;
function  StringToWideChar(const source:string; dest: PWideChar; destsize:Integer):PWideChar;
function  UpperCase(const S:string):string;

function  StrToCurr(st:string):currency;
function  StrToFloat(st:string):extended;
function  StrToInt(st:string):integer;
function  StrToIntDef(st:string; default:integer):integer;
function  StrToIntRange(st: string; min,max:longint):longint;

procedure Val(st:string; var x; code:integer);

function  FloatToStr(value:extended):string;
function  FloatToStrF(value:extended; format: TFloatFormat; precision, digits: integer):string;
function  FormatFloat(format:string; value:extended):string;

function  IntToHex(Value:integer; Digits:integer):string;
function  IntToStr(value:integer):string;

procedure Str(X [:width [:decimals]]; var st:string);

function  NewString(const s:string):PString;
procedure DisposeStr(p:PString);
procedure AssignStr(var p:PString; const s:String);
procedure AppendStr(var dest:string; const s: string);
function  CompareStr(const s1,s2:string):integer;
function  CompareText(const s1,s2:string):integer;
function  AnsiCompareStr(const s1,s2:string):integer;

{ Asciiz strings }

function  CharToOem(str, oemstr: PChar): Bool;
function  CharToOemBuff(str, oemstr: PChar; MaxLen: longint): Bool;
function  OemToChar(oemstr: string; str:PChar):bool;
function  OemToCharBuff(oemstr, str: PChar; maxlen: LongInt): bool;

function  StrAlloc(size: cardinal):PChar;
function  StrBufSize(str:PChar):cardinal;
function  StrCat(dest, source:PChar):PChar;
function  StrComp(s1, s2:PChar):Integer;
function  StrCopy(dest, source: PChar):PChar;
function  StrDispose(str: PChar);
function  StrECopy(dest, src:PChar):PChar;
function  StrEnd(str: PChar):PChar;
function  StrIComp(s1, s2:PChar):PChar;
function  StrLCat(dest, source:PChar; maxlen:word):PChar;
function  StrLComp(s1, s2:PChar; maxlen:cardinal):integer;
function  StrLCopy(dest, src:PChar; MaxLen: word):PChar;
function  StrLen(str:PChar):Cardinal;
function  StrLIComp(s1,s2:PChar; MaxLen:Word):PChar;
function  StrLower(s:PChar):PChar;
function  StrMove(dest,src:PChar; count:Word):PChar;
function  StrNew(Str:PChar):PChar;
function  StrPas(str:PChar):string;
function  StrPCopy(str:PChar;  s:string):PChar;
function  StrPLCopy(dest:PChar; const src:string; maxlen:Cardinal):PChar;
function  StrPos(s1,s2:PChar):PChar;
function  StrRScan(s:PChar; c:Char):PChar;
function  StrScan(s:PChar; c:Char):PChar;
function  StrUpper(s:PChar):PChar;

  Windows Kernel Mode RTL

ULONG
  RtlAnsiStringToUnicodeSize(
    IN PANSI_STRING  AnsiString
    );

NTSTATUS
  RtlAnsiStringToUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PANSI_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

NTSTATUS
  RtlAppendUnicodeStringToString(
    IN OUT PUNICODE_STRING  Destination,
    IN PUNICODE_STRING  Source
    );

NTSTATUS
  RtlAppendUnicodeToString(
    IN OUT PUNICODE_STRING  Destination,
    IN PCWSTR  Source
    );

LONG
  RtlCompareUnicodeString(
    IN PUNICODE_STRING  String1,
    IN PUNICODE_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );

VOID
  RtlCopyUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCUNICODE_STRING  SourceString
    );

BOOLEAN
  RtlEqualUnicodeString(
    IN CONST UNICODE_STRING  *String1,
    IN CONST UNICODE_STRING  *String2,
    IN BOOLEAN  CaseInSensitive
    );

VOID
  RtlFreeUnicodeString(
    IN PUNICODE_STRING  UnicodeString
    );

VOID
  RtlInitEmptyUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCWSTR  Buffer,
    IN USHORT  BufferSize
    );

VOID
  RtlInitUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCWSTR  SourceString
    );

NTSTATUS
  RtlInt64ToUnicodeString(
    IN ULONGLONG  Value,
    IN ULONG  Base OPTIONAL,
    IN OUT PUNICODE_STRING  String
    );

NTSTATUS
  RtlIntegerToUnicodeString(
    IN ULONG  Value,
    IN ULONG  Base  OPTIONAL,
    IN OUT PUNICODE_STRING  String
    );

NTSTATUS
  RtlIntPtrToUnicodeString(
    ULONG_PTR  Value,
    ULONG  Base  OPTIONAL,
    PUNICODE_STRING  String
    );

BOOLEAN
  RtlPrefixUnicodeString(
    IN PUNICODE_STRING  String1,
    IN PUNICODE_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );

NTSTATUS
  RtlStringFromGUID(
    IN REFGUID  Guid,
    OUT PUNICODE_STRING  GuidString
    );

ULONG
  RtlUnicodeStringToAnsiSize(
    PUNICODE_STRING  UnicodeString
    );

NTSTATUS
  RtlUnicodeStringToAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

NTSTATUS
  RtlUnicodeStringToInteger(
    IN PUNICODE_STRING  String,
    IN ULONG  Base  OPTIONAL,
    OUT PULONG  Value
    );

NTSTATUS
  RtlUnicodeToUTF8N(
    __out_opt PCHAR  UTF8StringDestination,
    __in ULONG  UTF8StringMaxByteCount,
    __out PULONG  UTF8StringActualByteCount,
    __in PCWCH  UnicodeStringSource,
    __in ULONG  Unicode

NTSTATUS
  RtlUpcaseUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

NTSTATUS
  RtlUTF8ToUnicodeN(
    __out_opt PWSTR  UnicodeStringDestination,
    __in ULONG  UnicodeStringMaxByteCount,
    __out PULONG  UnicodeStringActualByteCount,
    __in PCCH  UTF8StringSource,
    __in ULONG  UTF8StringByteCount
    );

ULONG
  RtlxAnsiStringToUnicodeSize(
    PANSI_STRING  AnsiString
    );

ULONG
  RtlxUnicodeStringToAnsiSize(
    PUNICODE_STRING  UnicodeString
    );

  NSString

+ (const NSStringEncoding *)  availableStringEncodings

+ (NSStringEncoding)defaultCStringEncoding
+ (NSString *)localizedNameOfStringEncoding:(NSStringEncoding)encoding
+ (id)localizedStringWithFormat:(NSString *)format ...
+ (NSString *)pathWithComponents:(NSArray *)components
+ (id)string

+ (id)stringWithCharacters:(const unichar *)chars length:(NSUInteger)length
+ (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc
                        error:(NSError **)error
+ (id)stringWithContentsOfFile:(NSString *)path usedEncoding:(NSStringEncoding *)enc
                        error:(NSError **)error
+ (id)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc
                        error:(NSError **)error
+ (id)stringWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc
                        error:(NSError **)error

+ (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc
+ (id)stringWithFormat:(NSString *)format, ...

+ (id)stringWithString:(NSString *)aString

+ (id)stringWithUTF8String:(const char *)bytes

- (BOOL)boolValue
- (BOOL)canBeConvertedToEncoding:(NSStringEncoding)encoding

- (NSString *)capitalizedString
- (NSComparisonResult)caseInsensitiveCompare:(NSString *)aString
- (unichar)characterAtIndex:(NSUInteger)index
- (NSString *)commonPrefixWithString:(NSString *)aString
            options:(NSStringCompareOptions)mask
- (NSComparisonResult)compare:(NSString *)aString
- (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask

- (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask
                    range:(NSRange)range
- (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask
                    range:(NSRange)range locale:(id) locale
- (NSUInteger)completePathIntoString:(NSString **)outputName caseSensitive:(BOOL)flag
        matchesIntoArray:(NSArray **)outputArray filterTypes:(NSArray *)filterTypes
- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator
- (NSArray *)componentsSeparatedByString:(NSString *)separator
- (const char *)cStringUsingEncoding:(NSStringEncoding)encoding
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding allowLossyConversion:(BOOL)flag
- (NSString *)decomposedStringWithCanonicalMapping
- (NSString *)decomposedStringWithCompatibilityMapping
- (NSString *)description
- (double)doubleValue
- (void)enumerateLinesUsingBlock:(void (^)(NSString *line, BOOL *stop))block
- (void)enumerateSubstringsInRange:(NSRange)range options:(NSStringEnumerationOptions)opts
    usingBlock:(void (^)(NSString *substring, NSRange substringRange,
    NSRange enclosingRange, BOOL *stop))block
- (NSStringEncoding)fastestEncoding
- (const char *)fileSystemRepresentation
- (float)floatValue
- (BOOL)getBytes:(void *)buffer maxLength:(NSUInteger)maxBufferCount
        usedLength:(NSUInteger *)usedBufferCount
        encoding:(NSStringEncoding)encoding
        options:(NSStringEncodingConversionOptions)options
        range:(NSRange)range remainingRange:(NSRangePointer)leftover
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange
- (BOOL)getCString:(char *)buffer maxLength:(NSUInteger)maxBufferCount
        encoding:(NSStringEncoding)encoding
- (BOOL)getFileSystemRepresentation:(char *)buffer maxLength:(NSUInteger)maxLength
- (void)getLineStart:(NSUInteger *)startIndex end:(NSUInteger *)lineEndIndex
        contentsEnd:(NSUInteger *)contentsEndIndex forRange:(NSRange)aRange
- (void)getParagraphStart:(NSUInteger *)startIndex end:(NSUInteger *)endIndex
        contentsEnd:(NSUInteger *)contentsEndIndex forRange:(NSRange)aRange
- (NSUInteger)hash
- (BOOL)hasPrefix:(NSString *)aString
- (BOOL)hasSuffix:(NSString *)aString
- (id)init
- (id)initWithBytes:(const void *)bytes length:(NSUInteger)length
        encoding:(NSStringEncoding)encoding
- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length
        encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)flag
- (id)initWithCharacters:(const unichar *)characters length:(NSUInteger)length
- (id)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length
        freeWhenDone:(BOOL)flag
- (id)initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc
        error:(NSError **)error
- (id)initWithContentsOfFile:(NSString *)path usedEncoding:(NSStringEncoding *)enc
        error:(NSError **)error
- (id)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc
        error:(NSError **)error
- (id)initWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc
        error:(NSError **)error
- (id)initWithCString:(const char *)nullTerminatedCString
        encoding:(NSStringEncoding)encoding
- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
- (id)initWithFormat:(NSString *)format ...
- (id)initWithFormat:(NSString *)format arguments:(va_list)argList
- (id)initWithFormat:(NSString *)format locale:(id)locale ...
- (id)initWithFormat:(NSString *)format locale:(id)locale arguments:(va_list)argList
- (id)initWithString:(NSString *)aString
- (id)initWithUTF8String:(const char *)bytes
- (NSInteger)integerValue
- (int)intValue
- (BOOL)isAbsolutePath
- (BOOL)isEqualToString:(NSString *)aString
- (NSString *)lastPathComponent
- (NSUInteger)length
- (NSUInteger)lengthOfBytesUsingEncoding:(NSStringEncoding)enc

- (NSRange)lineRangeForRange:(NSRange)aRange
- (NSComparisonResult)localizedCaseInsensitiveCompare:(NSString *)aString
- (NSComparisonResult)localizedCompare:(NSString *)aString
- (NSComparisonResult)localizedStandardCompare:(NSString *)string
- (long long)longLongValue
- (NSString *)lowercaseString
- (NSUInteger)maximumLengthOfBytesUsingEncoding:(NSStringEncoding)enc
- (NSRange)paragraphRangeForRange:(NSRange)aRange
- (NSArray *)pathComponents
- (NSString *)pathExtension
- (NSString *)precomposedStringWithCanonicalMapping
- (NSString *)precomposedStringWithCompatibilityMapping
- (id)propertyList
- (NSDictionary *)propertyListFromStringsFileFormat
- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet
- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet
        options:(NSStringCompareOptions)mask
- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet
        options:(NSStringCompareOptions)mask range:(NSRange)aRange
- (NSRange)rangeOfComposedCharacterSequenceAtIndex:(NSUInteger)anIndex
- (NSRange)rangeOfComposedCharacterSequencesForRange:(NSRange)range
- (NSRange)rangeOfString:(NSString *)aString
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask
        range:(NSRange)aRange
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask
        range:(NSRange)searchRange locale:(NSLocale *)locale
- (NSStringEncoding)smallestEncoding
- (NSString *)stringByAbbreviatingWithTildeInPath
- (NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
- (NSString *)stringByAppendingFormat:(NSString *)format ...
- (NSString *)stringByAppendingPathComponent:(NSString *)aString
- (NSString *)stringByAppendingPathExtension:(NSString *)ext
- (NSString *)stringByAppendingString:(NSString *)aString
- (NSString *)stringByDeletingLastPathComponent
- (NSString *)stringByDeletingPathExtension
- (NSString *)stringByExpandingTildeInPath
- (NSString *)stringByFoldingWithOptions:(NSStringCompareOptions)options
        locale:(NSLocale *)locale
- (NSString *)stringByPaddingToLength:(NSUInteger)newLength
        withString:(NSString *)padString startingAtIndex:(NSUInteger)padIndex
- (NSString *)stringByReplacingCharactersInRange:(NSRange)range
        withString:(NSString *)replacement
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
        withString:(NSString *)replacement
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
        withString:(NSString *)replacement options:(NSStringCompareOptions)options
        range:(NSRange)searchRange
- (NSString *)stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
- (NSString *)stringByResolvingSymlinksInPath
- (NSString *)stringByStandardizingPath
- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set
- (NSArray *)stringsByAppendingPaths:(NSArray *)paths
- (NSString *)substringFromIndex:(NSUInteger)anIndex
- (NSString *)substringToIndex:(NSUInteger)anIndex
- (NSString *)substringWithRange:(NSRange)aRange
- (NSString *)uppercaseString
- (const char *)UTF8String
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile
        encoding:(NSStringEncoding)enc error:(NSError **)error
- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)useAuxiliaryFile
        encoding:(NSStringEncoding)enc error:(NSError **)error

enum {
   NSASCIIStringEncoding = 1,
   NSNEXTSTEPStringEncoding = 2,
   NSJapaneseEUCStringEncoding = 3,
   NSUTF8StringEncoding = 4,
   NSISOLatin1StringEncoding = 5,
   NSSymbolStringEncoding = 6,
   NSNonLossyASCIIStringEncoding = 7,
   NSShiftJISStringEncoding = 8,
   NSISOLatin2StringEncoding = 9,
   NSUnicodeStringEncoding = 10,
   NSWindowsCP1251StringEncoding = 11,
   NSWindowsCP1252StringEncoding = 12,
   NSWindowsCP1253StringEncoding = 13,
   NSWindowsCP1254StringEncoding = 14,
   NSWindowsCP1250StringEncoding = 15,
   NSISO2022JPStringEncoding = 21,
   NSMacOSRomanStringEncoding = 30,
   NSUTF16StringEncoding = NSUnicodeStringEncoding,
   NSUTF16BigEndianStringEncoding = 0x90000100,
   NSUTF16LittleEndianStringEncoding = 0x94000100,
   NSUTF32StringEncoding = 0x8c000100,
   NSUTF32BigEndianStringEncoding = 0x98000100,
   NSUTF32LittleEndianStringEncoding = 0x9c000100,
   NSProprietaryStringEncoding = 65536
};

  ATL  CComBSTR

class CComBSTR
{
public:
    BSTR m_str;

    CComBSTR() throw()
    CComBSTR(_In_ int nSize)
    CComBSTR(_In_ int nSize, _In_opt_count_(nSize) LPCOLESTR sz)
    CComBSTR(_In_opt_ LPCOLESTR pSrc)
    CComBSTR(_In_ const CComBSTR& src)
    CComBSTR(_In_ REFGUID guid)
    CComBSTR& operator=(_In_ const CComBSTR& src)
    CComBSTR& operator=(_In_opt_ LPCOLESTR pSrc)
    ~CComBSTR() throw();
    unsigned int Length() const throw()
    unsigned int ByteLength() const throw()
    operator BSTR() const throw()
    BSTR* operator&() throw()
    BSTR Copy() const throw()
    _Check_return_ HRESULT CopyTo(_Inout_opt_ BSTR* pbstr) const throw()
    _Check_return_ HRESULT CopyTo(_Out_opt_ VARIANT *pvarDest) const throw()
    void Attach(_In_opt_ BSTR src) throw()
    BSTR Detach() throw()
    void Empty() throw()
    bool operator!() const throw()
    _Check_return_ HRESULT Append(_In_ const CComBSTR& bstrSrc) throw()
    _Check_return_ HRESULT Append(_In_opt_ LPCOLESTR lpsz) throw()
    _Check_return_ HRESULT AppendBSTR(_In_opt_ BSTR p) throw()
    _Check_return_ HRESULT Append(_In_opt_count_(nLen) LPCOLESTR lpsz, _In_ int nLen) throw()
    _Check_return_ HRESULT Append(_In_ char ch) throw()
    _Check_return_ HRESULT Append(_In_ wchar_t ch) throw()
    _Check_return_ HRESULT AppendBytes(_In_opt_count_(nLen) const char* lpsz, _In_ int nLen) throw()
    _Check_return_ HRESULT AssignBSTR(const BSTR bstrSrc) throw()
    _Check_return_ HRESULT ToLower() throw()
    _Check_return_ HRESULT ToUpper() throw()
    bool LoadString(_In_ HINSTANCE hInst, _In_ UINT nID) throw()
    bool LoadString(_In_ UINT nID) throw()
    CComBSTR& operator+=(_In_ const CComBSTR& bstrSrc)
    CComBSTR& operator+=(_In_opt_ LPCOLESTR pszSrc)
    bool operator<(const CComBSTR& bstrSrc) const throw()
    bool operator<(LPCOLESTR pszSrc) const
    bool operator<(LPOLESTR pszSrc) const
    bool operator>(const CComBSTR& bstrSrc) const throw()
    bool operator>(LPCOLESTR pszSrc) const
    bool operator>(_In_z_ LPOLESTR pszSrc) const
    bool operator!=(const CComBSTR& bstrSrc) const throw()
    bool operator!=(LPCOLESTR pszSrc) const
    bool operator!=(int nNull) const throw()
    bool operator!=(_In_z_ LPOLESTR pszSrc) const
    bool operator==(const CComBSTR& bstrSrc) const throw()
    bool operator==(LPCOLESTR pszSrc) const
    bool operator==(_In_z_ LPOLESTR pszSrc) const
    bool operator==(int nNull) const throw()
    CComBSTR(_In_opt_ LPCSTR pSrc)
    CComBSTR(_In_ int nSize, _In_opt_count_(nSize) LPCSTR sz)
    _Check_return_ HRESULT Append(_In_opt_ LPCSTR lpsz) throw()
    CComBSTR& operator=(_In_opt_ LPCSTR pSrc)
    bool operator<(_In_opt_ LPCSTR pszSrc) const
    bool operator>(_In_opt_ LPCSTR pszSrc) const
    bool operator!=(_In_opt_ LPCSTR pszSrc) const
    bool operator==(_In_opt_ LPCSTR pszSrc) const
    _Check_return_ HRESULT WriteToStream(_Inout_ IStream* pStream) throw()
    _Check_return_ HRESULT ReadFromStream(_Inout_ IStream* pStream) throw()
    static bool LoadStringResource(_In_ HINSTANCE hInstance, _In_ UINT uID, _Inout_ _Deref_post_opt_valid_ BSTR& bstrText) throw()
    static bool LoadStringResource(_In_ UINT uID, _Inout_ _Deref_post_opt_valid_ BSTR& bstrText) throw()
    _Success_(SUCCEEDED(return)) HRESULT BSTRToArray(_Deref_out_ LPSAFEARRAY *ppArray) throw()
    _Check_return_ HRESULT ArrayToBSTR(_In_ const SAFEARRAY *pSrc) throw()
    static ULONG GetStreamSize(BSTR bstr)
};


70.2.7. КОЛЛЕКЦИИ

THIS SECTION IS UNDER CONSTRUCTION

Коллекции  --+---- Линейные ----+--- с индексным ---+--- Cловарь
         |                  |    доступом	    +--- Hash таблица
         |                  |
         |                  +--- с прямым  ----+---- Массив
         |			|    доступом      +---- Структура
         |			|		   +---- Файл
         |		        |
         |			+-- с последоват --+---- Файл
         |			     доступом      +---- Список
         |					   +---- Stack
             |					   +---- Очередь (Queue)
         |					   +---- Очередь с приоритетами
         |
         +-- Нелинейные ---+-- Иерархические --+---- Дерево
                        |		   +---- Пирамида
                        |
                   +- Неиерархические -+---- Набор   (Set)
                           +---- Граф

  Кортежи

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

Требования к кортежам
    создать кортеж
    выбрать элемент из кортежа
    скопировать кортеж

Пример: C++ шаблон std::pair

template <class T1, class T2>
class pair
{
public:
    T1	first;
    T2	second;

    pair(const T1& f = T1(),
         const T2& s = T2()) : first(f), second(s)	{}

    pair(const pair<T1,T2>& x);	// конструктор копии
};

template <class T1, class T2>
pair<T1,T2> make_pair(const T1& x, const T2& y)
{
    pair<T1,T2>  p(x,y);
    return	p;		// by value
}

template <class T1, class T2>
inline bool operator == (const pair<T1,T2>& x, const pair<T1,T2> &y)
{
    return x.first == y.first && x.second == y.second;
}

template <class T1, class T2>
inline bool operator != (const pair<T1,T2>& x, const pair<T1,T2> &y)
{
    return !(x == y);
}

template <class T1, class T2>
inline bool operator < (const pair<T1,T2>& x, const pair<T1,T2> &y)
{
    return (x.first < y.first) ||  !(y.first < x.first) && (x.second < y.second);
}

template <class T1, class T2>
inline bool operator > (const pair<T1,T2>& x, const pair<T1,T2> &y)
{
    return y < x;
}

template <class T1, class T2>
inline bool operator <= (const pair<T1,T2>& x, const pair<T1,T2> &y)
{
    return !(y < x);
}

template <class T1, class T2>
inline bool operator >= (const pair<T1,T2>& x, const pair<T1,T2> &y)
{
    return !(x < y);
}

В принципе pair - это не предел. Например в Boost есть шаблон tuple определенный
для размерностей от 0 до 10.

template <class A, class B, class C> class tuple
{
public:
    A first;
    B second;
    C third;

    tuple(const A& f = A(),
          const B& s = B(),
          const C& t = C()) : first(f), second(s), third(t) { }

//	tuple(const tuple<A,B,C>& x);	// Copy constructor
};

template <class A, class B, class C>
A  get<0>(tuple<A,B,C>& x)
{
    return	x.first;
};

template <class A, class B, class C>
B  get<1>(tuple<A,B,C>& x)
{
    return  x.second;
}

template <class A, class B, class C>
C get<2>(tuple<A,B,C>& x)
{
    return	x.third;
}

  Списки

    Head/Tail Reference
    Head/Tail dummy node
    Circular
        never empty

    Списки
        Создать список
        Удалить список
            удалить все элементы в списке

        Добавить элемент в список
            в начало
            в конец
            на указанную позицию

        Удалить элемент из списка
            указанный элемент
            первый элемент
            последний элемент

        Создать элемент списка
        Удалить элемент списка

        Является ли список пустым?

        Взять Nй элемент из списка

        Получить итератор
            Итерационный обход списка
            Итерационный обход списка по признаку
                или с callback по элементам
                    predicate

        Сортировка списка
            prediate

        Поиск в списке
            Найти элемент в списке по признаку
                первый
                последний
                Nй
            тоже но рекурсивно если список содержи списки.

  Односвязный список

Добавление элемента к списку:

Удаление элемента из списка:

  Двухсвязный список

  Паралельный поиск в списке

Если есть счетчик элементов то можно искать
с начала и с конца паралельно

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

То же самое - только однонаправленный список

  Дека

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

  Паралельный поиск в неупорядоченной деке

Один процессор ищет с начала, другой с конца
(нужны длинна что бы найти границу где остановиться)

Несколько процессоров обрабатывают блоки деки,
прыгая через них

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

  Стек

  FIFO (Очередь)

  Cyclic List

Как правило удобнее всего использовать двунаправленные Cyclic List.
Head item обычно инициализируется указателями на самого себя.

  Generic List

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

  Multilist

Есть несколько связей одних и тех же данных по разным критериям

  Списки и деки как контейнеры

// STL <list>

template <class T, class A = allocator<T>>
class list
{
public:
    typedef	A	allocator_type;
    typedef typename A::pointer	  pointer;
    typedef typename A::const_pointer const_pointer;
    typedef typename A::reference	  reference;
    typedef typename A::const_reference const_reference;

    typedef ... iterator;		// Implementation depended
    typedef ... const_iterator;
    typedef ... size_type;
    typedef ... difference_type;
    typedef ... reverse_iterator;
    typedef ... const_reverse_iterator;

    list();
    explicit list(const A& al);
    explicit list(size_tyoe  n);

    list(size_type n, const T& v);
    list(size_type n, const T& v, const A& al);
    list(const list&);

    template <class InIt> list(InIt first, InIt last);
    template <class InIt> list(InIt first, InIt last, const A& al);

    iterator begin();
    const_iterator begin() const;
    iterator end();
    const_iterator end() const;

    reverse_iterator rbegin();
    const_reverse_iterator rbegin() const;
    reverse_iterator rend();
    const_reverse_iterator rend() const;

    void resize(size_type n);
    void resize(size_type n, T x);

    size_type size() const;
    size_type max_size() const;
    bool  empty() const;
    A  get_allocator() const;

    reference front();
    const_reference front() const;
    reference back();
    const_reference back()  const;

    void push_front(const T& x);
    void pop_front();
    void push_back(const T& x);
    void pop_back();

    template <class InIt> assign(InIt first, InIt last);
    void assign(size_type n, const T& x);

    iterator insert(iterator it, const T&x);
    void	insert(iterator it, size_type n, const T& x);

    template <class InIt>
    void insert(iterator it, InIt first, InIt last);

    iterator erase(iterator it);
    iterator erase(iterator first, iterator last);
    void	clear();
    void	swap(list& x);
    void	splice(iterator it, list& x);
    void	splice(iterator it, list& x, iterator fisrt);
    void	splice(iterator it, list& x, iterator first, iterator last);

    void	remove(const T& v);

    template <class Pred> void remove_if(Pred pr);

    void	unique();
    template <class Pred> void unique(Pred pr);

    void 	merge(list& x);
    template <class Pred> void merge(list& x, Pred pr);

    void	sort();
    template <class Pred> void sort(Pred pr);
    void	reverse();
};

template <class T, class A> bool operator == (const list<T,A>& l, const list<T,A>&r);
template <class T, class A> bool operator != (const list<T,A>& l, const list<T,A>&r);
template <class T, class A> bool operator >  (const list<T,A>& l, const list<T,A>&r);
template <class T, class A> bool operator >= (const list<T,A>& l, const list<T,A>&r);
template <class T, class A> bool operator < (const list<T,A>& l, const list<T,A>&r);
template <class T, class A> bool operator <= (const list<T,A>& l, const list<T,A>&r);

template <class T, class A> void swap(list<T,A>& l, list<T,A>& r);

// <deque>

template <class T, class Allocator = allocator<T> >
class deque
{
public:

    typedef Allocator allocator_type;

    ...	const_iterator;
    ...	const_pointer;
    ...	const_reference;
    ...	const_reverse_iterator;
    ...	difference_type;
    ...	iterator;
    ...	pointer;
    ...	reference;
    ...	reverse_iterator;
    ...	size_type;
    ...	value_type;

    deque();
    explicit deque(const Allocator& _Al);
    explicit deque(size_type _Count);
    deque(size_type _Count, const T& _Val);
    deque(size_type _Count, const T& _Val, const Allocator& _Al);
    deque(const deque& _Right);
    template<class InputIterator> deque(InputIterator _First, InputIterator _Last);
    template<class InputIterator> deque(InputIterator _First, InputIterator _Last,
                              const Allocator& _Al);

    template<class InputIterator>  void assign(InputIterator _First, InputIterator _Last);
    void assign(size_type _Count,  const T& _Val);

    reference at(size_type _Pos);
    const_reference at(size_type _Pos) const;

    reference operator[](size_type _Pos);
    const_reference operator[](size_type _Pos) const;

    reference back();
    const_reference back() const;
    reference front();
    const_reference front() const;

    void pop_back();
    void pop_front();

    void push_back(const T& _Val);
    void push_front(const T& _Val);

    const_iterator begin() const;
    iterator begin();
    const_iterator end() const;
    iterator end();

    const_reverse_iterator rbegin() const;
    reverse_iterator rbegin();
    const_reverse_iterator rend() const;
    reverse_iterator rend();

    void clear();

    bool empty() const;
    size_type size() const;
    size_type max_size() const;
    Allocator get_allocator() const;

    void resize(size_type _Newsize);
    void resize(size_type _Newsize, T _Val);

    iterator erase(iterator _Where);
    iterator erase(iterator _First, iterator _Last);
    iterator insert(iterator _Where,  const T& _Val);
    void insert(iterator _Where, size_type _Count, const T& _Val);
    template<class InputIterator>  void insert(iterator _Where,
                           InputIterator _First, InputIterator _Last);
    void swap(deque<T, Allocator>& _Right);
    friend void swap(deque<T, Allocator>& _Left, deque<T, Allocator>& _Right)

    template<class Type, class Allocator>
    void swap(deque< Type, Allocator>& _Left, deque< Type, Allocator>& _Right);
};

template <class T, class A> bool operator == (const deque<T,A>& l, const deque<T,A>&r);
template <class T, class A> bool operator != (const deque<T,A>& l, const deque<T,A>&r);
template <class T, class A> bool operator < (const deque<T,A>& l, const deque<T,A>&r);
template <class T, class A> bool operator <= (const deque<T,A>& l, const deque<T,A>&r);
template <class T, class A> bool operator > (const deque<T,A>& l, const deque<T,A>&r);
template <class T, class A> bool operator >= (const deque<T,A>& l, const deque<T,A>&r);

template <class T, class A> void swap(deque<T,A>& l, deque<T,A>& r);

// STL <stack>  адаптер

template <class T, class Cont=deque<T> >
class stack
{
public:
    typedef Cont container_type;
    typedef typename Cont::value_type value_type;
    typedef typename Cont::size_type  size_type;

    stack();
    explicit stack(const container_type& cont);
    bool  empty() const;
    size_type size() const;
    value_type& top();
    const value_type& top();
    void push(const value_type& x);
    void pop();
}

  Потокобезопасность в коллекциях

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

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

void insert()
{
    lock(collection)
    thread_unsafe_insert(collection, item)
    unlock(collection)
}

item delete()
{
    lock(collection)
    item temp = thread_unsafe_remove(collection)
    unlock(collection)
    return	temp
}

Надо сказать, что STL коллекции не являются потокобезопасными.

На самом деле удобно иметь суперобъекты которые покрывают контейнер
и при этом имеют следущие локи:
    SpinLock  - для того что бы отслеживать счетчик ссылок
    RWLock    - для доступа к элементам

class SharedContainer
{
    private:
        CRWLock* _rwLock;
        CSpinLock* _spinLock;
        volatile u32 retainCount;
    Container* _container;	  // Non-thread safe container

        CSharedContainer(const CSharedObject& obj) {};
        CSharedContainer& operator=(const CSharedContainer& obj) { return *this; };

    public:
        CSharedContainer();
        virtual ~CSharedContainer();

        virtual void retain();    // increment ref count
        virtual void release();   // decrement ref count, destroy if 0
        virtual void destroy();

        virtual void lockShared();   // access primitives
        virtual void lockExclusive();
        virtual void sharedToExclusive();
        virtual void exclusiveToShared();
        virtual void unlock();
    };

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

  Разряженные массивы

  Sparse Array

Разреженные массивы:
1D - в общем то это список.

Типичный формат элемента:
    ELEMENT*   NEXT
    int	   INDEX
    T	   DATA

  Sparse Matrix

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

Возможны разные имплементации:

Форматы данных для строки и столбца:

Формат данных для элемента:

  Hash

Функция хэширования для строк

    Hash = (Hash * 17 + char[i]) mod TableSize
    TableSize - лучше выбирать простое число

Функция Вайнбергера
    Loop
    {
        Hash = (Hash << 4) + char[i]
        G = Hash & 0xf0000000
        if (G != 0)
        {
            Hash = (Hash ^ (G >> 24)) ^ G
    }
    Hash = Hash mod TableSize

  Чистая Hash структура

    Чисто Hash структура
        все храниться в массиве
            зондирование (если 2 items с одним значением)
                линейное	h(k,i) = (h(k) + i) mod m
                квадратичное	h(k,i) = (h(k) + c1*i + c2*i^2) mod m
                двойное		h(k,i) = (h(k) + h2(k)*i) mod m

  Chained hash структура

    Chained Hash структура
        первый hop - hash-таблица
        остальные список

  MHT (Multilevel Hash Table)

  Hash контейнеры

hash_set<Key,HashFunc,EqualKey,Allocator>
hash_map<Key, T, HashFunc, EqualKey, Allocator>

hash_multiset<Key,HashFunc,EqualKey,Allocator>
hash_multimap<Key, T, HashFunc, EqualKey, Allocator>

Hashed контейнеры также введены в TR1. они называются
unordered_set и unordered_map соответственно.

unordered_set<Key,HashFunc,EqualKey,Allocator>
unordered_multiset<Key,HashFunc,EqualKey,Allocator>
unordered_map<Key, T, HashFunc, EqualKey, Allocator>
unordered_multimap<Key, T, HashFunc,EqualKey,Allocator>

 --------------------------------------------------------------
                                HP 	SGI	 	MS
 container		STL	STL     STL	TR1	VS2010
 --------------------------------------------------------------
hash_set		-	-	+	-	+
hash_multiset		-	-	+	-	+
hash_map		-	-	+	-	+
hash_multimap		-	-	+	-	+
unordered_set		-	-	-	+	+
unordered_multiset	-	-	-	+	+
unordered_map		-	-	-	+	+
unordered_multiset	-	-	-	+	+
 --------------------------------------------------------------

// STL TR1 <unordered_set>

namespace tr1
{

template<class _Kty,	// key type (same as value type)
    class _Tr,	// comparator predicate type
    class _Alloc,	// actual allocator type (should be value allocator)
    bool _Mfl>	// true if multiple equivalent keys are permitted
    class _Uset_traits
        : public _Container_base
    {	// traits required to make _Hash behave like a set
public:
    typedef _Kty _Val_type;
    typedef _Kty key_type;
    typedef _Kty value_type;
    typedef _Tr key_compare;

    typedef typename _Alloc::template rebind<value_type>::other
        allocator_type;

    enum
        {	// make multi parameter visible as an enum constant
        _Multi = _Mfl};

    _Uset_traits()
        : comp()
        {	// construct with default comparator
        }

    _Uset_traits(const _Tr& _Traits)
        : comp(_Traits)
        {	// construct with specified comparator
        }

    typedef key_compare value_compare;

    static const _Kty& _Kfn(const value_type& _Val)
        {	// return entire value as key
        return (_Val);
        }

    _Tr comp;	// the comparator predicate for keys
    };

template<class _Kty,
    class _Hasher = _STD tr1::hash<_Kty>,
    class _Keyeq = _STD equal_to<_Kty>,
    class _Alloc = _STD allocator<_Kty> >
    class unordered_set
        : public _Hash<_Uset_traits<_Kty,
            _Hash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false> >
    {	// hash table of key values, unique keys
public:
    typedef unordered_set<_Kty, _Hasher, _Keyeq, _Alloc> _Myt;
    typedef _Hash_compare<_Kty, _Hasher, _Keyeq> _Mytraits;
    typedef _Hash<_Uset_traits<_Kty,
        _Mytraits, _Alloc, false> > _Mybase;
    typedef _Hasher hasher;
    typedef _Kty key_type;
    typedef _Keyeq key_equal;
    typedef _Mytraits key_compare;	// extra

    typedef typename _Mybase::allocator_type allocator_type;
    typedef typename _Mybase::size_type size_type;
    typedef typename _Mybase::difference_type difference_type;
    typedef typename _Mybase::pointer pointer;
    typedef typename _Mybase::const_pointer const_pointer;
    typedef typename _Mybase::reference reference;
    typedef typename _Mybase::const_reference const_reference;
    typedef typename _Mybase::iterator iterator;
    typedef typename _Mybase::const_iterator const_iterator;
    typedef typename _Mybase::value_type value_type;

    typedef typename _Mybase::iterator local_iterator;
    typedef typename _Mybase::const_iterator const_local_iterator;

    unordered_set()
    unordered_set(const _Myt& _Right)
    explicit unordered_set(size_type _Buckets)
    unordered_set(size_type _Buckets, const hasher& _Hasharg)
    unordered_set(size_type _Buckets, const hasher& _Hasharg,
    unordered_set(size_type _Buckets, const hasher& _Hasharg,
    template<class _Iter>
        unordered_set(_Iter _First, _Iter _Last)
    template<class _Iter>
        unordered_set(_Iter _First, _Iter _Last,
            size_type _Buckets)
    template<class _Iter>
        unordered_set(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg)
    template<class _Iter>
        unordered_set(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg)
    template<class _Iter>
        unordered_set(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg, const allocator_type& _Al)
    _Myt& operator=(const _Myt& _Right)
    unordered_set(_Myt&& _Right)
    _Myt& operator=(_Myt&& _Right)
    void swap(_Myt& _Right)
    void swap(_Myt&& _Right)
    hasher hash_function() const
    key_equal key_eq() const
    void erase(const_iterator _Where)
    size_type erase(const key_type& _Keyval)
    void erase(const_iterator _First, const_iterator _Last)

};

template<class _Kty,
    class _Hasher,
    class _Keyeq,
    class _Alloc>
    void swap(unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Left,
        unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Right)

template<class _Kty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_set<_Kty, _Tr, _Alloc>& _Left,
        unordered_set<_Kty, _Tr, _Alloc>&& _Right)

template<class _Kty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_set<_Kty, _Tr, _Alloc>&& _Left,
        unordered_set<_Kty, _Tr, _Alloc>& _Right)

template<class _Kty,
    class _Hasher = _STD tr1::hash<_Kty>,
    class _Keyeq = _STD equal_to<_Kty>,
    class _Alloc = _STD allocator<_Kty> >
    class unordered_multiset
        : public _Hash<_Uset_traits<_Kty,
            _Hash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, true> >
    {	// hash table of key values, non-unique keys
public:
    typedef unordered_multiset<_Kty, _Hasher, _Keyeq, _Alloc> _Myt;
    typedef _Hash_compare<_Kty, _Hasher, _Keyeq> _Mytraits;
    typedef _Hash<_Uset_traits<_Kty,
        _Mytraits, _Alloc, true> > _Mybase;
    typedef _Hasher hasher;
    typedef _Kty key_type;
    typedef _Keyeq key_equal;
    typedef _Mytraits key_compare;	// extra

    typedef typename _Mybase::allocator_type allocator_type;
    typedef typename _Mybase::size_type size_type;
    typedef typename _Mybase::difference_type difference_type;
    typedef typename _Mybase::pointer pointer;
    typedef typename _Mybase::const_pointer const_pointer;
    typedef typename _Mybase::reference reference;
    typedef typename _Mybase::const_reference const_reference;
    typedef typename _Mybase::iterator iterator;
    typedef typename _Mybase::const_iterator const_iterator;
    typedef typename _Mybase::value_type value_type;

    unordered_multiset()
    unordered_multiset(const _Myt& _Right)
    explicit unordered_multiset(size_type _Buckets)
    unordered_multiset(size_type _Buckets, const hasher& _Hasharg)
    unordered_multiset(size_type _Buckets, const hasher& _Hasharg,
    unordered_multiset(size_type _Buckets, const hasher& _Hasharg,
    template<class _Iter>
        unordered_multiset(_Iter _First, _Iter _Last)
    template<class _Iter>
        unordered_multiset(_Iter _First, _Iter _Last,
            size_type _Buckets)
    template<class _Iter>
        unordered_multiset(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg)
    template<class _Iter>
        unordered_multiset(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg)
    template<class _Iter>
        unordered_multiset(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg, const allocator_type& _Al)
    _Myt& operator=(const _Myt& _Right)
    unordered_multiset(_Myt&& _Right)
    _Myt& operator=(_Myt&& _Right)

    template<class _Valty>
        iterator insert(_Valty&& _Val)
    template<class _Valty>
        typename _STD tr1::enable_if<!_STD tr1::is_same<const_iterator,
            typename _STD tr1::remove_reference<_Valty>::type>::value,
                iterator>::type
        insert(const_iterator _Where, _Valty&& _Val)
    void swap(_Myt& _Right)
    void swap(_Myt&& _Right)
    hasher hash_function() const
    key_equal key_eq() const
    void erase(const_iterator _Where)
    size_type erase(const key_type& _Keyval)
    void erase(const_iterator _First, const_iterator _Last)
    iterator insert(const value_type& _Val)
    iterator insert(const_iterator _Where, const value_type& _Val)
    template<class _Iter>
        void insert(_Iter _First, _Iter _Last)
};

template<class _Kty,
    class _Hasher,
    class _Keyeq,
    class _Alloc>
    void swap(unordered_multiset<_Kty, _Hasher, _Keyeq, _Alloc>& _Left,
        unordered_multiset<_Kty, _Hasher, _Keyeq, _Alloc>& _Right)

template<class _Kty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_multiset<_Kty, _Tr, _Alloc>& _Left,
        unordered_multiset<_Kty, _Tr, _Alloc>&& _Right)
template<class _Kty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_multiset<_Kty, _Tr, _Alloc>&& _Left,
        unordered_multiset<_Kty, _Tr, _Alloc>& _Right)

}	// namespace tr1

// STL TR1 <unordered_map>

namespace tr1
{

template<class _Kty,	// key type
    class _Ty,	// mapped type
    class _Tr,	// comparator predicate type
    class _Alloc,	// actual allocator type (should be value allocator)
    bool _Mfl>	// true if multiple equivalent keys are permitted
    class _Umap_traits
        : public _Container_base
    {	// traits required to make _Hash behave like a map
public:
    typedef pair<_Kty, _Ty> _Val_type;
    typedef _Kty key_type;
    typedef pair<const _Kty, _Ty> value_type;
    typedef _Tr key_compare;

    typedef typename _Alloc::template rebind<value_type>::other
        allocator_type;

    enum
        {	// make multi parameter visible as an enum constant
        _Multi = _Mfl};

    _Umap_traits()
        : comp()
        {	// construct with default comparator
        }

    _Umap_traits(const _Tr& _Traits)
        : comp(_Traits)
        {	// construct with specified comparator
        }

    class value_compare
        : public binary_function<value_type, value_type, bool>
        {	// functor for comparing two element values
        friend class _Umap_traits<_Kty, _Ty, _Tr, _Alloc, _Mfl>;

    public:
        bool operator()(const value_type& _Left,
            const value_type& _Right) const
            {	// test if _Left precedes _Right by comparing just keys
            return (comp(_Left.first, _Right.first));
            }

        value_compare(const key_compare& _Traits)
            : comp(_Traits)
            {	// construct with specified predicate
            }

    protected:
        key_compare comp;	// the comparator predicate for keys
        };

    template<class _Ty1,
        class _Ty2>
        static const _Kty& _Kfn(const _STD pair<_Ty1, _Ty2>& _Val)
        {	// extract key from element value
        return (_Val.first);
        }

    _Tr comp;	// the comparator predicate for keys
    };

        // TEMPLATE CLASS unordered_map
template<class _Kty,
    class _Ty,
    class _Hasher = _STD tr1::hash<_Kty>,
    class _Keyeq = _STD equal_to<_Kty>,
    class _Alloc = _STD allocator<_STD pair<const _Kty, _Ty> > >
    class unordered_map
        : public _Hash<_STD tr1::_Umap_traits<_Kty, _Ty,
            _Hash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false> >
    {	// hash table of {key, mapped} values, unique keys
public:
    typedef unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc> _Myt;
    typedef _Hash_compare<_Kty, _Hasher, _Keyeq> _Mytraits;
    typedef _Hash<_STD tr1::_Umap_traits<_Kty, _Ty,
        _Mytraits, _Alloc, false> > _Mybase;
    typedef _Hasher hasher;
    typedef _Kty key_type;
    typedef _Ty mapped_type;
    typedef _Ty referent_type;	// extra
    typedef _Keyeq key_equal;
    typedef _Mytraits key_compare;	// extra

    typedef typename _Mybase::allocator_type allocator_type;
    typedef typename _Mybase::size_type size_type;
    typedef typename _Mybase::difference_type difference_type;
    typedef typename _Mybase::pointer pointer;
    typedef typename _Mybase::const_pointer const_pointer;
    typedef typename _Mybase::reference reference;
    typedef typename _Mybase::const_reference const_reference;
    typedef typename _Mybase::iterator iterator;
    typedef typename _Mybase::const_iterator const_iterator;
    typedef typename _Mybase::value_type value_type;

    typedef typename _Mybase::iterator local_iterator;
    typedef typename _Mybase::const_iterator const_local_iterator;

    unordered_map()
    unordered_map(const _Myt& _Right)
    explicit unordered_map(size_type _Buckets)
    unordered_map(size_type _Buckets, const hasher& _Hasharg)
    unordered_map(size_type _Buckets, const hasher& _Hasharg,
    unordered_map(size_type _Buckets, const hasher& _Hasharg,
        const _Keyeq& _Keyeqarg,
        const allocator_type& _Al)
    template<class _Iter>
        unordered_map(_Iter _First, _Iter _Last)
    template<class _Iter>
        unordered_map(_Iter _First, _Iter _Last,
            size_type _Buckets)
    template<class _Iter>
        unordered_map(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg)
    template<class _Iter>
        unordered_map(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg)
    template<class _Iter>
        unordered_map(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg, const allocator_type _Al)
    _Myt& operator=(const _Myt& _Right)
    unordered_map(_Myt&& _Right)
    _Myt& operator=(_Myt&& _Right)
    mapped_type& operator[](key_type&& _Keyval)
    void swap(_Myt& _Right)
    void swap(_Myt&& _Right)
    hasher hash_function() const
    key_equal key_eq() const
    void erase(const_iterator _Where)
    size_type erase(const key_type& _Keyval)
    void erase(const_iterator _First, const_iterator _Last)
    mapped_type& operator[](const key_type& _Keyval)
    mapped_type& at(const key_type& _Keyval)
    const mapped_type& at(const key_type& _Keyval) const
};

template<class _Kty,
    class _Ty,
    class _Hasher,
    class _Keyeq,
    class _Alloc>
    void swap(unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Left,
        unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Right)

template<class _Kty,
    class _Ty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_map<_Kty, _Ty, _Tr, _Alloc>& _Left,
        unordered_map<_Kty, _Ty, _Tr, _Alloc>&& _Right)

template<class _Kty,
    class _Ty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_map<_Kty, _Ty, _Tr, _Alloc>&& _Left,
        unordered_map<_Kty, _Ty, _Tr, _Alloc>& _Right)

template<class _Kty,
    class _Ty,
    class _Hasher = _STD tr1::hash<_Kty>,
    class _Keyeq = _STD equal_to<_Kty>,
    class _Alloc = _STD allocator<_STD pair<const _Kty, _Ty> > >
    class unordered_multimap
        : public _Hash<_STD tr1::_Umap_traits<_Kty, _Ty,
            _Hash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, true> >
    {	// hash table of {key, mapped} values, non-unique keys
public:
    typedef unordered_multimap<_Kty, _Ty, _Hasher, _Keyeq, _Alloc> _Myt;
    typedef _Hash_compare<_Kty, _Hasher, _Keyeq> _Mytraits;
    typedef _Hash<_STD tr1::_Umap_traits<_Kty, _Ty,
        _Mytraits, _Alloc, true> > _Mybase;
    typedef _Hasher hasher;
    typedef _Kty key_type;
    typedef _Ty mapped_type;
    typedef _Ty referent_type;	// extra
    typedef _Keyeq key_equal;
    typedef _Mytraits key_compare;	// extra

    typedef typename _Mybase::allocator_type allocator_type;
    typedef typename _Mybase::size_type size_type;
    typedef typename _Mybase::difference_type difference_type;
    typedef typename _Mybase::pointer pointer;
    typedef typename _Mybase::const_pointer const_pointer;
    typedef typename _Mybase::reference reference;
    typedef typename _Mybase::const_reference const_reference;
    typedef typename _Mybase::iterator iterator;
    typedef typename _Mybase::const_iterator const_iterator;
    typedef typename _Mybase::value_type value_type;

    typedef typename _Mybase::iterator local_iterator;
    typedef typename _Mybase::const_iterator const_local_iterator;

    unordered_multimap()
    unordered_multimap(const _Myt& _Right)
    explicit unordered_multimap(size_type _Buckets)
    unordered_multimap(size_type _Buckets, const hasher& _Hasharg)
    unordered_multimap(size_type _Buckets, const hasher& _Hasharg,
        const _Keyeq& _Keyeqarg)
    unordered_multimap(size_type _Buckets, const hasher& _Hasharg,
        const _Keyeq& _Keyeqarg, const allocator_type& _Al)
    template<class _Iter>
        unordered_multimap(_Iter _First, _Iter _Last)
    template<class _Iter>
        unordered_multimap(_Iter _First, _Iter _Last,
            size_type _Buckets)
    template<class _Iter>
        unordered_multimap(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg)
    template<class _Iter>
        unordered_multimap(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg)
    template<class _Iter>
        unordered_multimap(_Iter _First, _Iter _Last,
            size_type _Buckets, const hasher& _Hasharg,
            const _Keyeq& _Keyeqarg, const allocator_type _Al)
    _Myt& operator=(const _Myt& _Right)
    unordered_multimap(_Myt&& _Right)
    _Myt& operator=(_Myt&& _Right)
    template<class _Valty>
        iterator insert(_Valty&& _Val)
    template<class _Valty>
        typename _STD tr1::enable_if<!_STD tr1::is_same<const_iterator,
            typename _STD tr1::remove_reference<_Valty>::type>::value,
                iterator>::type
        insert(const_iterator _Where, _Valty&& _Val)
    void swap(_Myt& _Right)
    void swap(_Myt&& _Right)
    hasher hash_function() const
    key_equal key_eq() const
    void erase(const_iterator _Where)
    size_type erase(const key_type& _Keyval)
    void erase(const_iterator _First, const_iterator _Last)
    iterator insert(const value_type& _Val)
    iterator insert(const_iterator _Where, const value_type& _Val)
    template<class _Iter>
        void insert(_Iter _First, _Iter _Last)
};

template<class _Kty,
    class _Ty,
    class _Hasher,
    class _Keyeq,
    class _Alloc>
    void swap(unordered_multimap<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Left,
        unordered_multimap<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Right)
template<class _Kty,
    class _Ty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_multimap<_Kty, _Ty, _Tr, _Alloc>& _Left,
        unordered_multimap<_Kty, _Ty, _Tr, _Alloc>&& _Right)

template<class _Kty,
    class _Ty,
    class _Tr,
    class _Alloc> inline
    void swap(unordered_multimap<_Kty, _Ty, _Tr, _Alloc>&& _Left,
        unordered_multimap<_Kty, _Ty, _Tr, _Alloc>& _Right)

}	// namespace tr1

  Circular Buffer (Ring)

Есть два указателя на начало и на конец.
Когда они равны - circular buffer пустой.

Варианты имплементации:
1) Head, Tail, использовать только N-1 элемент,
2) Head, Tail, bool(Full or Empty)
3) Head, Tail, Number of elements used
4) Head, Tail  (special values for free buffer)

  Skip List

Skip List - список с пропусками
некоторые элементы содержат указатели сильно вперед.
(лучше делать двойной).

Как правило уровень глубины выбираем случайным числом.

  Поиск

  Вставка

  Удаление

Логическое удаление:

Физическое удаление:

  Delete Minimum

  Skip Queue

  Очередь с приоритетами  (Куча/Пирамида)

Думаете что очередь с приоритетами выгляжит так:

C одного конца кладут
С другово забирают наиболее приоритетный item
В пределах одного приоритета получаем (FIFO)

Можно и так если число приоритетов мало (например меньше 5).

Реально применяются кучи

Пример адаптера для priority_queue:

template <class T, class Cont=vector<T>,
      class Pred=less<typename Cont::value_type> >
class piority_queue
{
public:
    typedef	Cont container_type;
            value_type
            size_type;

    priority_queue();
        // total 7 constructors

    bool  empty() const;
    size_type size() const;
    value_type& top();
    const value_type& top();
    void push(const value_type& x);
    void pop();

}

  Кучи

  Binary Heap

Куча (Пирамида)
    - Binary Tree
    - Min heap: каждый child > = parent
      Max heap: каждый child < = parent

    Минимальный/максимальный элемент кучи - root

  Представление бинарной кучи в виде массива

    Parent(i)     = floor(i/2)
    LeftChild(i)  = 2i
    RightChild(i) = 2i + 1

  Добавление элемента в кучу

Вставка происходит в первую свободную позицию
Если нарушается очередность то происходит ротация с родителем
(и так на всем пути в вверх (upheap)).
"Nodes достигают своего уровня некомпетентности"

Upheap:

Собственно Decrease Node - это тот же самый простой upheap.

  Удаление элемента из кучи

Удаление root элемента из кучи:
    удаление root элемента
    замена его на элемент из правого поддерева
    Downheap - пока не будет порядка

  Merge

Быстрого алгоритма нету, все порядка O(n)

  Pairing Heap

Pairing Heap - это min/max куча, которая имеет более 2 childs у node.
И как правило организована как список childs.

Node structure:
    Child		указатель на первого child
    Left/Right	указатель на siblings (Double-linked list)
            (Left у первой node на parent)
    Data

Пример кучи с 3 узлами (частный случай pairing heap)

  Увеличение приоритета узла

  Удаление случайного узла

  LeftList Heaps

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

npl Null path length

npl(x) - длинна кратчайшего пути от узла X до узла у которого нет 2х детей

    npl(null) = -1
    npl(leaf) = 0
    npl(single-node-child) = 0

    npl(left-child(x)) >= npl(right-child(x))

Проблемы LeftList heaps:
    - надо хранить и обрабатывать npl
    - правая часть часто становиться очень тяжелой

  Skew Heaps

Скорректированная версия LeftList Heap.
Merge всегда меняет детей при фиксировании правой части

  Binomal Heap

Основная идея - не должно сущуществовать больше 1 дерева
определанного ранга.

Слияние

Удаление

  Fibonacci Heaps

Модифицированные биномальные кучи
    Множество куч
    Любое количество куч любого ранга
    Деревья  связаны double-linked списком, но не упорядоченны в список
    Содержит указатель на минимальный элемент
    Множество отмаркированных узлов (используются to keep heap flat)

Интенсивная консолидация деревьев после вставки
Ленивый отказ от консолидации до следующего delete-min

  Insert

Insert:
    Create new singleton tree
    Add to root list (Update min pointer (if necessary))

Insert (Lazy):

  Meld

    Concatentate two root lists
    Update min[H], n[H]

  Delete Min

Delete min:
    Delete min
    Meld it children into root list. Update min
    Consolidate trees so no two roots have same rank

Delete:

  Decrease Key

Decrease key:
    Case 1 [Heap order not violated]
        Decrease key of X
        Change heap min pointer (if need)

    Case 2  [Heap order is violated]
        Decrease key of X
        Cut tree rooted at X, meld it into root list and unmark
    Case 2a	if parent of X is unmarked (hasn't yet lost a child) mark it
    Case 2b if parent of X is marked, cut P, meld into root list and unmark
        (and do it recursively for all ancestors that lose a second child)

Decrease:

  Деревья

Операции над деревьями:
    добавление элемента
    удаление элемента
    сортировка
        автоматически при добавлении/удалении
            перебалансировка
    поиск
    обход

Собcтвенно два основных типа:
    внутренние (умещаются в память)
    внешние (частично храняться на других носителях)
от этого сильно зависит организация.

Почему в памяти практически всегда бинарные деревья?
Ведь чем больше ветвей от вершины - тем выгоднее по скорости.
Определяются оборудованием: если бы были эффективные команды по
мульчебранчеванию - то можно было бы такие делать.
(На IA-64 можно сделать похожие структуры используя VLIW/EPIC).
Но на большинстве оборудования такого нету.

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

  Бинарные деревья

Бинарное дерево: вставка 500 случайных элементов

Бинарное дерево: случайная вставка/удаление 250000 элементов

  Обход дерева

  Обход дерева в глубину

V - visit
L - left
R - right

возможные варианты:
VLR  LVR  LRV  VRL  RVL  RLV

VLR прямой просмотр		(префиксная форма)
LVR симметричный просмотр	(инфиксная форма)
LRV обратный просмотр		(постфиксная форма)

Просмотр	a + b	log x	n! 	a - (b * c)	(a < b) | (c < d)
 ---------------------------------------------------------------------------------
Прямой          + a b	log x   ! n	- a * b c	| < a b < c d
Симметричный    a + b	log x  	n !	a - b * c	a < b | c < d
Обратный        a b +	x log	n !	a b c * -	a b < c d < |
 ---------------------------------------------------------------------------------

  Обход дерева в ширину

  2-3 деревья

В дополнение к 2-node есть 3-node узлы

Вставка в 2-3 дерево:

Удаление из 2-3 дерева:

  2-3-4 деревья

В дополнению к 2- и 3- узлам есть еще и 4 узлы:

Вставка:

Конвертация в Red-Black Tree:

  B-tree

delete:

join:

move:

search:

split:

  B+tree

  Сбалансированные деревья

Баланс происходит по высоте поддеревьев

Фактор сбалансированности узла дерева

левовысотный	-1
(левое поддерево выше на 1)

равновысотный   0
(оба поддерева равны по высоте)

правовысотный  +1
(правое поддерево выше на 1)

AVL деревья поддерживают факторы сбалансированности -1,0,+1

Например это не является сбалансированным деревом:

Деревья Фиббоначи поддерживают факторы сбалансированности -1,0
(см кучи Фибоначчи)

  Red-Black Tree

Красно-черные деревья

Свойства красно-черного дерева:
    Корень должен быть черным
    Потомки красного узла должны быть черными
    На всех ветвях дерева ведущих от его корня к листьям число черных узлов одинаково

Алгоритм добавления - максимум 2 поворота дерева
Алгоритм удаления   - максимум 3 поворота дерева

Все RBT для 1-4:

Все RBT для 5-6:

Все RBT для 7:

X - New node
P - Parent
S - Sibling
G - Grandparent

  Скошенные деревья

Splay Tree

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

В результате при доступе дерево улучшается.

Примитивные операции которые используются в Splay-Tree

Zig:

Zig-Zig:

Zig-Zag:

  AVL-деревья

Adelson-Velskii Landis (AVL)

Node
{
    int	data;
    Node*	Left;
    Node*   Right;
    int	balanceFactor;
}

Balance_Factor = height(Right_subtree) - height(Left_subtree)

У AVL дерева balance factor может быть только -1,0,1.

  AA-деревья

AA-Tree - это красно-черное дерево с доп условием
только один child может быть красным

Горизонтальные ссылки
    Node и Child одного уровня - всегда правое присоединение
    Не может быть больше 2 правых ссылок подряд
    Nodes на уровне 2 и выше должны иметь 2 Childs

Skew:

Split:

  k-d деревья

Multidimensional B-Tree.
    четные уровни бранчевания - по 1 ключу
    нечетные уровни бранчевания - по 2му ключу
    root - считаем четным

Строго говоря возможно большее количество измерений чем 2.

  QuadTree

Упрощенный вариант k-d деревьев.
Пространство делиться на 4.

  Trie

от слова ReTRIEval

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

Компактизированное Trie:

Patricia Trie:

  Treap

Treap - смешанная структура данных, которая является с одной стороны деревом,
    а с другой стороны кучей.

Использовалась в поисковых системах.

Split:

Join:

  Disjoint Set

Объединение:

Поиск:

Представление в виде списка:

Представление в виде массива:

  Контейнеры на базе деревьев

  Set

Set - множество значений. Значения уникальны.
Еще есть Multiset. В Multiset значения неуникальны.
В Set и Multiset значение является ключем.

  Map

В Map/Multimap ключ и значение разделены.
В Map ключ уникален (а значения могут и совпадать)
Еще есть Multimap (позволяет иметь неуникальные ключи).

    Set/Multiset
    Map/Multimap
    Hash/Multihash
        то же что и для списка, но просто
        Добавить элемент
        Удалить  элемент
        Найти элемент по признаку

Представления для Set/Multiset, Map/Multimap могут быть как списки, так и деревья.
Деревья с точки зрения скорости предпочтительнее в большинстве случаев.

  Индексация нечисловыми типами

Понятно, что в конце концов для массива происходит свертка
в индекс. Но если это не массив, то индексатор может быть
интереснее.

  Контейнеры основанные на деревьях

template <class Key, class Type, class Traits = less<Key>,
          class Allocator=allocator<pair <const Key, Type> > >
class map
{
public:

    ....	// typedefs

    map();
    explicit map(const Traits& _Comp);
    map(const Traits& _Comp, const Allocator& _Al);
    map(const map<Key, Type, Traits, Allocator>& _Right);
    template<class InputIterator>  map(InputIterator _First, InputIterator _Last);
    template<class InputIterator>  map(InputIterator _First, InputIterator _Last,
                       const Traits& _Comp);
    template<class InputIterator>  map(InputIterator _First, InputIterator _Last,
                       const Traits& _Comp, const Allocator& _Al);

    void clear();
    bool empty() const;
    size_type size() const;
    size_type max_size() const;
    size_type count(const Key& _Key) const;

    allocator_type get_allocator( ) const;
    key_compare key_comp( ) const;
    value_compare value_comp( ) const;

    Type& operator[](const Key& _Key);

    const_iterator begin() const;
    iterator begin();
    const_iterator end() const;
    iterator end();
    const_reverse_iterator rbegin() const;
    reverse_iterator rbegin();
    const_reverse_iterator rend() const;
    reverse_iterator rend();

    pair <const_iterator, const_iterator> equal_range (const Key& _Key) const;
    pair <iterator, iterator> equal_range (const Key& _Key);

    iterator lower_bound(const Key& _Key);
    const_iterator lower_bound(const Key& _Key) const;
    iterator upper_bound(const Key& _Key);
    const_iterator upper_bound(const Key& _Key) const;

    iterator erase(iterator _Where);
    iterator erase(iterator _First, iterator _Last);
    size_type erase(const key_type& _Key);

    iterator find(const Key& _Key);
    const_iterator find(const Key& _Key) const;

    pair <iterator, bool> insert(const value_type& _Val);
    iterator insert(iterator _Where,const value_type& _Val);
    template<class InputIterator> void insert(InputIterator _First,InputIterator _Last);

    void swap(map<Key, Type, Traits, Allocator>& _Right);
};

// ... compare operators and swap

  Графы

Графы рассматриваются начиная с секции 55.50.


70.2.8. ОБОБЩЕННЫЕ АЛГОРИТМЫ

THIS SECTION IS UNDER CONSTRUCTION

  Итераторы

Итератор - абстракция для работы обобщенных алгоритмов

Собственно абстракция бывает разной:

Итераторы в C++:

Итераторы в Java:

Типы по направлению:
    Forward
    Backward
    BiDirectional

Типы по перемещению:
    Sequential
    Random Access

  Неизменяющие алгоритмы

  Поиск

template<class InputIterator, class Type>
    InputIterator find(
        InputIterator _First,
              InputIterator _Last,
              const Type& _Val
       );

  Поиск по предикату

template<class InputIterator, class Predicate>
       InputIterator find_if(
              InputIterator _First,
              InputIterator _Last,
              Predicate _Pred
       );

  Поиск соседних элементов

template<class ForwardIterator>
    ForwardIterator adjacent_find(
              ForwardIterator _First,
              ForwardIterator _Last
       );

  Поиск соседних элементов по предикату

template<class ForwardIterator , class BinaryPredicate>
    ForwardIterator adjacent_find(
              ForwardIterator _First,
              ForwardIterator _Last,
              BinaryPredicate _Comp
       );

  Поиск первого вхождения группы элементов

template<class ForwardIterator1, class ForwardIterator2>
       ForwardIterator1 find_first_of(
              ForwardIterator1 _First1,
              ForwardIterator1 _Last1,
              ForwardIterator2 _First2,
              ForwardIterator2 _Last2
       );

template<class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
       ForwardIterator1 find_first_of(
              ForwardIterator1 _First1,
              ForwardIterator1 _Last1,
              ForwardIterator2 _First2,
              ForwardIterator2 _Last2,
              BinaryPredicate _Comp
       );

  Поиск подстоки

template<class ForwardIterator1, class ForwardIterator2>
       ForwardIterator1 search(
              ForwardIterator1 _First1,
              ForwardIterator1 _Last1,
              ForwardIterator2 _First2,
              ForwardIterator2 _Last2
       );

  Поиск максимального элемента

template<class ForwardIterator>
       ForwardIterator max_element(
              ForwardIterator _First,
              ForwardIterator _Last
       );

template<class ForwardIterator, class BinaryPredicate>
       ForwardIterator max_element(
              ForwardIterator _First,
              ForwardIterator _Last,
              BinaryPredicate _Comp
       );

  Поиск минимального элемента

template<class ForwardIterator>
       ForwardIterator min_element(
              ForwardIterator _First,
              ForwardIterator _Last
       );

template<class ForwardIterator, class BinaryPredicate>
       ForwardIterator min_element(
              ForwardIterator _First,
              ForwardIterator _Last,
              BinaryPredicate _Comp
       );

  Подсчет числа вхождений элемента

template<class InputIterator, class Type>
    typename iterator_traits<InputIterator>::difference_type count(
              InputIterator _First,
              InputIterator _Last,
              const Type& _Val
       );

template<class InputIterator, class Predicate>
       typename iterator_traits<InputIterator>::difference_type count_if(
              InputIterator _First,
              InputIterator _Last,
              Predicate _Pred
       );

  Сравнение диапазонов

template<class InputIterator1, class InputIterator2>
    bool equal(
              InputIterator1 _First1,
              InputIterator1 _Last1,
              InputIterator2 _First2
          );

template<class InputIterator1, class InputIterator2, class BinaryPredicate>
       bool equal(
              InputIterator1 _First1,
              InputIterator1 _Last1,
              InputIterator2 _First2,
              BinaryPredicate _Comp
          );

TODO:
    find_end
    mismatch
    lexicographical_compare

template<class ForwardIterator1, class ForwardIterator2>
   ForwardIterator1 find_end(
      ForwardIterator1 _First1,
      ForwardIterator1 _Last1,
      ForwardIterator2 _First2,
      ForwardIterator2 _Last2
   );
template<class ForwardIterator1, class ForwardIterator2, class Pred>
   ForwardIterator1 find_end(
      ForwardIterator1 _First1,
      ForwardIterator1 _Last1,
      ForwardIterator2 _First2,
      ForwardIterator2 _Last2,
      Pred _Comp
   );

template<class InputIterator1, class InputIterator2>
   pair<InputIterator1, InputIterator2> mismatch(
      InputIterator1 _First1,
      InputIterator1 _Last1,
      InputIterator2 _First2
    );
template<class InputIterator1, class InputIterator2, class BinaryPredicate>
   pair<InputIterator1, InputIterator2> mismatch(
      InputIterator1 _First1,
      InputIterator1 _Last1,
      InputIterator2 _First2
      BinaryPredicate _Comp
   );

template<class InputIterator1, class InputIterator2>
   bool lexicographical_compare(
      InputIterator1 _First1,
      InputIterator1 _Last1,
      InputIterator2 _First2,
      InputIterator2 _Last2
   );
template<class InputIterator1, class InputIterator2, class BinaryPredicate>
   bool lexicographical_compare(
      InputIterator1 _First1,
      InputIterator1 _Last1,
      InputIterator2 _First2,
      InputIterator2 _Last2,
      BinaryPredicate _Comp
   );

  Изменяющие алгоритмы

  Копирование

template<class InputIterator, class OutputIterator>
   OutputIterator copy(
      InputIterator _First,
      InputIterator _Last,
      OutputIterator _DestBeg
   );

template<class BidirectionalIterator1, class BidirectionalIterator2>
   BidirectionalIterator2 copy_backward(
      BidirectionalIterator1 _First,
      BidirectionalIterator1 _Last,
      BidirectionalIterator2 _DestEnd
   );

  Заполнение

template<class ForwardIterator, class Type>
   void fill(
      ForwardIterator _First,
      ForwardIterator _Last,
      const Type& _Val
   );

template<class OutputIterator, class Size, class Type>
   void fill_n(
      OutputIterator _First,
      Size _Count,
      const Type& _Val
   );

template<class ForwardIterator, class Generator>
   void generate(
      ForwardIterator _First,
      ForwardIterator _Last,
      Generator _Gen
   );

template<class OutputIterator, class Diff, class Generator>
   void generate_n(
      OutputIterator _First,
      Diff _Count,
      Generator _Gen
   );

  Замена

template<class ForwardIterator, class Type>
   void replace(
      ForwardIterator _First,
      ForwardIterator _Last,
      const Type& _OldVal,
      const Type& _NewVal
   );

template<class ForwardIterator, class Predicate, class Type>
   void replace_if(
      ForwardIterator _First,
      ForwardIterator _Last,
      Predicate _Pred,
      const Type& _Val
   );

  Обмен диапазонами

template<class ForwardIterator1, class ForwardIterator2>
   ForwardIterator2 swap_ranges(
      ForwardIterator1 _First1,
      ForwardIterator1 _Last1,
      ForwardIterator2 _First2
   );

  Реверсирование

template<class BidirectionalIterator>
   void reverse(
      BidirectionalIterator _First,
      BidirectionalIterator _Last
   );

  Вращение

template<class ForwardIterator>
   void rotate(
      ForwardIterator _First,
      ForwardIterator _Middle,
      ForwardIterator _Last
   );

  Партиционирование

template<class BidirectionalIterator, class Predicate>
   BidirectionalIterator partition(
      BidirectionalIterator _First,
      BidirectionalIterator _Last,
      Predicate _Comp
   );

template<class BidirectionalIterator, class Predicate>
   BidirectionalIterator stable_partition(
      BidirectionalIterator _First,
      BidirectionalIterator _Last,
      Predicate _Pred
   );

  Сортировка

template<class RandomAccessIterator>
   void sort(
      RandomAccessIterator _First,
      RandomAccessIterator _Last
   );
template<class RandomAccessIterator, class Predicate>
   void sort(
      RandomAccessIterator _First,
      RandomAccessIterator _Last,
      Predicate _Comp
   );

template<class BidirectionalIterator>
   void stable_sort(
      BidirectionalIterator _First,
      BidirectionalIterator _Last
   );
template<class BidirectionalIterator, class BinaryPredicate>
   void stable_sort(
      BidirectionalIterator _First,
      BidirectionalIterator _Last,
      BinaryPredicate _Comp
   );

  Случайное перемешивание

template<class RandomAccessIterator>
   void random_shuffle(
      RandomAccessIterator _First,
      RandomAccessIterator _Last
      );
template<class RandomAccessIterator, class RandomNumberGenerator>
   void random_shuffle(
      RandomAccessIterator _First,
      RandomAccessIterator _Last,
      RandomNumberGenerator& _Rand
   );

  Трансформация

template<class InputIterator, class OutputIterator, class UnaryFunction>
   OutputIterator transform(
      InputIterator _First1,
      InputIterator _Last1,
      OutputIterator _Result,
      UnaryFunction _Func
      );
template<class InputIterator1, class InputIterator2, class OutputIterator,
   class BinaryFunction>
   OutputIterator transform(
      InputIterator1 _First1,
      InputIterator1 _Last1,
      InputIterator2 _First2,
      OutputIterator _Result,
      BinaryFunction _Func
   );

  Множественные алгоритмы

  Объединение множеств

  Пересечение множеств

  Разность множеств

Нессиметричная операция

  Симметрическая разность множеств


70.2.9. ПОТОКОБЕЗОПАСНЫЕ КОЛЛЕКЦИИ

Для переносимости нужна прослойка для locks итд.

Что вообще должно быть защищено в коллекции?

    Собственно владение коллекцией
        счетчик ссылок
            защищенный mutexом

    Защита доступа к коллекции
        rwlock

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

    Конструктор итератора
        lock

    Деструктор итератора
        unlock

Проще всего этого добиться обверткой стандартного контейнера

Кроме этого с точки зрения производительности возможны улучшения для
внутренней структуры.

Например добавление в список может не захватывать RWlock на запись,
а захватить на чтение, после чего захватить специальный mutex на последний
элемент (что бы нельзя было добавлять паралельно), затем сформировать новый
элемент и атомарно (interlocked operations) добавить его в список.

Так же можно защищать мьютексом каждый элемент коллекции (но это плохо -
количество waitable mutex небесконечно, а spin-mutex имеет проблемы с
вытеснением.

Удаление может осуществляться установкой флага, что элемент удален,
с последующей сборкой мусора в специальной нити по отсутсвию лока или в
состоянии перехода upgrade/downgrade.


70.3. ОБЩИЕ ВОПРОСЫ

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

В этой секции будут рассматриваться алгоритмы не связанные со
структурами данных

THIS SECTION IS UNDER CONSTRUCTION

  Оценка сложности алгоритмов

  P и NP

  Рекурсия

    Рекурсия
        Простая
        Хвостовая
    Итерации

Тут всплювает любопытная структура данных (Infinite List) которая используется для
таких случаев динамического программирования.
Сущность следушая:
    Есть индексатор,
    Если данные для индекса уже посчитаны то они возвращаются
    Если нет то они вычисляются, помещаются в этот list, а потом возвращаются.


70.3.1. ГЕНЕРАЦИЯ СЛУЧАЙНЫХ И ПСЕВДОСЛУЧАЙНЫХ ЧИСЕЛ

  Псевдослучайные числа

  Метод Фон-Неймана

Метод Неймана (метод средних квадратов)
    возьмите N-значное число
    возведите его в квадрат
    возьмите N-средних цифр

  Метод Лемера

Метод Лемера

    X{n+1} = (a * X{n} + c) mod M

    M - лучше всего простое

    a = 134775813
    c = 1
    M = 2^32

Парк и Миллер
    a = 16807
    M = 2^32-1

Обычно для инициализации генератора берут число соответсвующее времени.
    Randomize(-Time)

Свойства геренатора ПСЧ

    Однородность

  Аддитивные генераторы

    +-----+
    |     |<-- X
    |     |<-- Y
    +-----+
    массив ПСЧ

        [X] = [X] + [Y]
        will return [X]
        X++
        Y--

  Случайные числа

Скалиброванный генератор белого шума

Случайные события
    нажатие клавиши на клавиатуре
    перемещения мыши

    +---------+-----+---+
    |         |     |   |
    +---------+-----+---+
              берем среднюю часть времени
          младшая если через TSC то несколько младших бит могут
          быть синхронизированны на некоторых архитектурах с шиной

  Генерация ПСЧ с заданным законом распределения

THIS SECTION IS UNDER CONSTRUCTION

Распределение Пуассона
Экспотенциальное распределение

  RTL для работы с ПСЧ

// stdlib.h

int rand( void );
void srand(unsigned int seed);

Типовая настройка SEED:

    rand(-time());	// правда в последнее время лучше просто от time()

// stdlib.h - UNIX

char *initstate(unsigned int seed, char *state, size_t size);
long random(void);
char *setstate(const char *state);
void srandom(unsigned int seed);

// Типовая тупая имплементация на примере Borland C++ 3.1

#define MULTIPLIER      0x015a4e35L
#define INCREMENT       1

static  long    Seed = 1;

void srand(unsigned seed)
{
        Seed = seed;
}

int rand(void)
{
        Seed = MULTIPLIER * Seed + INCREMENT;
        return((int)(Seed >> 16) & 0x7fff);
}


70.3.2. АЛГОРИТМЫ СОРТИРОВКИ

THIS SECTION IS UNDER CONSTRUCTION

  Проблематика сортировки

Упорядоченье бывает разное.
    Порядок может быть и не строгим

    Например case-insensitive
        'A'
    и	'a'   - это одно и то же

Что делать с одинаковыми элементами?
    Случайное упорядочение
    Упорядочение в порядке следования в исходной структуре данных

  Типы сортировки

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

Сортировка
    in-place
        не требующая дополнительной памяти
    Требующая дополнительной памяти

Сортировка
    stable
        элементы с одинаковыми значениями будет в результате лежать в
        том же порядке относительно друг друга, как в исходных данных
    non-stable
        элементы с одинаковыми значениями могут лежать как угодно
        относительно друг друга.

Вспомогательные операции как правило используемые сортировкой
    Partitioning
        разделение данных на 2 партиции относительно некоторого базового
        элемента (в одной большие элементы, в другой меньшие элементы)
        [реально в жизни есть 3я - с тем же значением]
    Merge
        склейка двух отсортированых блоков данных вместе  в совместно
        отсортированном порядке.

    O(N^2)	Selection Sort
        Buble Sort
        Insertion Sort

    O(N *log(N))
        Merge Sort
        Quick Sort

  Insertion Sort

  Median Sort

  QuickSort

  Heap Sort

  Counting Sort

  Bucket Sort

  Selection Sort

THIS SECTION IS UNDER CONSTRUCTION

  Merge Sort

  Паралельная сортировка

    Партиционирование
    Сортировка партиций

    Сортировка блоков
    Merge отсортированных блоков

Сортировка блоков (может осуществляться паралельно)

Merge отсортированных блоков
(в основном может осуществляться параллельно, но есть ньюансы)

TODO: Много ньюансов

  Сортирующие сети

THIS SECTION IS UNDER CONSTRUCTION

  Интерфейсы для сортировки

// stdlib.h
void qsort(
   void *base,
   size_t num,
   size_t width,
   int (__cdecl *compare )(const void *, const void *)
);

void qsort_s(		// with context
   void *base,
   size_t num,
   size_t width,
   int (__cdecl *compare )(void *, const void *, const void *),
   void * context
);


70.3.3. АЛГОРИТМЫ ПОИСКА

THIS SECTION IS UNDER CONSTRUCTION

    Sequental Search
    Binary Search
        только для уже упорядоченных данных
    Binary-Tree Search

    не забудьте посмотреть главу про Hash структуры

  Проблематика поиска

Поиск в отсорированных данных дает один результат только в случае
уникальных данных.

А реально в случае неуникальных данных у нас возможны 4 варианта:
    simple search

  Простой поиск

Мы выходим на какой-то элемент с указанным значением

  Поиск нижней границы

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

  Поиск верхней границы

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

  Поиск диапазона равных значений

  Поиск ближайших соответсвий

Java NavigateMap интерфейс поддерживает поиск ближайших
соответсвий:

// Java

interface NavigateMap<K,V>
{
    ...

Map.Entry<K,V> ceilingEntry(K obj);  // наименьший key, такой что K >= obj
K	       ceilingKey(K obj);

Map.Entry<K,V> floorEntry(K obj);    // наибольший key, такой что K <= obj
K	       floorKey(K obj);

Map.Entry<K,V> higherEntry(K obj);   // наименьший key, такой что K > obj
K	       higherKey(K obj);

Map.Entry<K,V> lowerEntry(K obj);    // наибольший key, такой что K < obj
K	       lowerKey(K obj);

    ...
}

  Типы поиска

  Последовательный поиск

  Бинарный поиск

// stdlib.h
void *bsearch(
   const void *key,
   const void *base,
   size_t num,
   size_t width,
   int ( __cdecl *compare ) ( const void *, const void *)
);

void *bsearch_s( 		// with context
   const void *key,
   const void *base,
   size_t num,
   size_t width,
   int ( __cdecl *compare ) ( void *, const void *, const void *),
   void * context
);

  Поиск с использованием hash

  Интерполяционный поиск

Для него нужно что бы ключ был целочисленный.

Например если данные распределены равномерно, то средний показатель
времени интерполяционного поиска порядка lg lg N

Например если у нас 10^6 элементов
    линейный поиск  ~ 5*10^5
    бинарный поиск  ~ 21
    интерполяционный поиск ~ 4.32

Проблема в том что как правило данные распределены неравномерно.


70.3.4. КОМБИНАТОРНЫЕ АЛГОРИТМЫ

THIS SECTION IS UNDER CONSTRUCTION

Генерация перестановок

next_permutation
prev_permutation

TODO: Структуры данных

(Генерация сочетаний)


70.4. НЕКОТОРЫЕ ИНФРАСТРУКТУРНЫЕ ВОПРОСЫ

В этой секции мы будем рассматривать вопросы связанные
с инфраструктурой программного обеспечения

    o   Обработка ошибок
    o   Разбор коммандной строки
    o   Потоки данных


70.4.1. ОБРАБОТКА ОШИБОК

THIS SECTION IS UNDER CONSTRUCTION

Вообще проблема делиться на 2 части:
    - интерфейс с системой или framework
    - пользовательские ошибки

Возможные способы:
    Глобальная переменная [errno]
        приходится выносить в TLS для многопоточных приложений
    Функция которая возвращает последнюю ошибку [GetLastError()]
    Все функции API возвращают статус [DOSERROR тип в OS/2]

Для пользовательских ошибок хочеться всю портянку ошибки от самого нижнего
уровня до верхнего вместе с комментариями.

Special values:
    Success	   	0		No errors
    OutOfMemory     1
    Undefined	2		default

Line Number Information (File, Line)
 Add(asciiz Filename, dword LineNumber)

Inload error codes
 Add(dword UserErrorCode)

Win32 error codes
 AddWin32Code(dword Win32Code)

HRESULTs
 Add(HRESULT hResult)

Text description
 Add(asciiz Text)

Filenames
 AddFilename(asciiz Text)

Sector numbers
 AddSector(qword Number, asciiz Text=0)

Cluster numbers
 AddCluster(qword Number,asciiz Text=0)

File Offset
 AddOffset(qword Number, asciiz Text=0)

Error  F()
{
    ...

    return	ERROR(FileNotFound).AddWin32Code(::GetLastError())
                   .Add("Configuration file not found")
                   .AddFilename(myfilename);
    ...
}

Error  G()
{

    Error e = GETERROR(F());
    if (!e)
    {
        e += "Can't load parameters";
        ...
        return	e;

    }
    return	0;		// success
}

---------------------- ERROR DESCRIPTION ----------------------
----------
0000: CODE       : = ImFileNotExist
0001: LINE NUMBER: 'c:\workcvs\imagemgm\base\win32\w32file.cpp', L= 140
0002: WIN32CODE  : = 00000002
0003: TEXT DESCRP: 'File not found'
0004: FILENAME   : 'c:\msnsusii.exe'
----------
0005: LINE NUMBER: 'c:\workcvs\imagemgm\base\win32\w32file.cpp', L= 564
0006: TEXT DESCRP: 'Factory can't open file'
----------
0007: LINE NUMBER: 'c:\workcvs\imagemgm\test\tw32file.cpp', L= 12
0008: TEXT DESCRP: 'FAIL: Problems with open test file'
---------------------- END  ERROR  ----------------------


70.4.3. ПОТОКИ ДАННЫХ

Потоки данных
    Обычные
        Без позиционирования
            Ввод
            Вывод
        С позициоированием
    Обвязки
        Компрессия
        Шифрование

    Вывод данных
        Предопределенные данные
            ends
            endl
    Управление потоком
        Манипуляторы
            flush

THIS SECTION IS UNDER CONSTRUCTION

  C++

    ios_base	состояние формата

    basic_ios<>	типы и трейты

    basic_iostream<>

template  >
class std::basic_ostream : virtual public basic_ios
{
    basic_ostream& operator<<(short n);
    ...
    basic_ostream& operator<<(float f);

    basic_ostream& put(Ch c);
    basic_ostream& write(const Ch* p, streamsize n);
}

typedef basic_ostream ostream;
typedef basic_ostream wostream;

ostream	cout;
ostream	cerr;
ostream	clog;

wostream wcout;
wostream wcerr;
wostream wclog;

template  >
class std::basic_istream : virtual public basic_ios
{
}

typedef basic_istream istream;
typedef basic_istream wistream;

istream	cin;
wistream wcin;

ostream& operator << (ostream& out, const T& val)
{
    ...
    return	out;
}

  C#

Адаптеры потоков
    StreamReader : TextReader
    StreamWriter : TextWriter
    StringReader : TextReader
    StringWriter : TextWriter
    BinaryReader
    BinaryWriter
    XmlReader
    XmlWriter

Потоки декораторы  : Stream
    DeflateStream
    GZipStream
    CryptoStream
    BufferedStream

Потоки с резервным хранилищем   : Stream
    FileStream
    MemoryStream
    UnmanagedMemoryStream
    IsolatedStorageStream : FileStream
    NetworkStream

  Java

Java:	InputStream
    OutputStream
        FileInputStream
        FileOutputStream
        ByteArrayInputStream
        ByteArrayOutputStream

        BufferedInputStream
        BufferedOutputStream

        PushbackInputStream

        SequenceInputStream	// сводит вместе несколько
                    // input streams

        PrintStream
        DataInputStream
        DataOutputStream


70.4.4. СЕРИАЛИЗАЦИЯ ОБЪЕКТОВ

THIS SECTION IS UNDER CONSTRUCTION

Сериализация простых объектов

Сериализация цепочек объектов

Сериализация и полиморфизм
    надо знать какой именно экземпляр объекта был сериализирован


70.5. К ВОПРОСАМ О ПАРАЛЛЕЛИЗАЦИИ АЛГОРИТМОВ

THIS SECTION IS UNDER CONSTRUCTION

  Партиционирование задачи

  Паралельный Search для упорядоченнных структур


70.6. ОСНОВНЫЕ ПАРАДИГМЫ

THIS SECTION IS UNDER CONSTRUCTION

    Процедурное программирование
        что вызвали то и сделалось.

    Событийное программирование
        пришло событие, выбрали его из очереди событий
        обрабатываем его

    Многонитевое программирование
        работают несколько нитей паралельно

    Паралельное программирование
        то же самое что мультинитевое но параллелит компилятор.

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


71. ЯЗЫКИ ПРОГРАММИРОВАНИЯ

Собственно основные подходы к языкам программирования различаются по
организации обработки данных:

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

    Декларативные
        Поток запросов
            Инструкция выполняется когда нужен ее результат
        (Prolog)

    Списочные
        Поток данных
            Инструкция выполняется когда готовы ее операнды
        (LISP)

    HDL (Hardware Description Languages)
        Поток с управлением по набору условий
        (VHDL, Verilog)

TODO: Не забыть про Smalltalk

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

Но не расчитывайте на то, что мы будем полно рассматривать какие-то из языков,
нас интересуют только отдельные моменты. Цель - получить представление о том,
что существует, а не рассмотреть конкретную имплементацию.
А так же поднять основные проблемы, с этим связанные.


71.1. ИМПЕРАТИВНЫЕ ЯЗЫКИ ПРОГРАММИРОВАНИЯ

THIS SECTION IS UNDER CONSTRUCTION

Поток управления - инструкция выполняется когда ей придет управление.

Наиболее известные императивные языки:

    FORTRAN
    BASIC
    PASCAL
    C
    C++
    Java
    C#
    Perl
    PHP
    Ruby
    итд


71.1.1. УПРАВЛЯЮШИЕ КОНСТРУКЦИИ

В этой и следущих секциях мы будем смотреть на управляюшие конструкции
языков программирования:

Поэтому надо научиться читать flowchart дианграммы хотя бы в примитивном виде.

Process - это обработка данных. Считается что кусок выполняется линейно от начала до конца.
Хотя при уровнях вложенности process может содержать в себе все что угодно - главное
что у него одна точка входа и одна точка выхода.

Decision - приниматься решение.

Далее в этой секции мы рассмотрим некоторые конструкции, которым не требуется
принимать решение:

THIS SECTION IS UNDER CONSTRUCTION

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

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

Переход может быть вперед, а может назад.
Например в ассемблере для BPF (Berkeley Packet Filters) назад переходить
нельзя - можно только вперед.

    GOTO	label

C

----------------------------
loop:
    ....
    goto	loop;
----------------------------

BASIC

----------------------------
10	GOTO	30
----------------------------

CODEGENERATION
Unconditional jump:
-----------------------------------------------------------------------
loop:                        		loop:
    .....                           	.........
goto	loop                                    jmp	loop
------------------------------------------------------------------------

Много лет ведуться Holy Wars на тему - можно ли использовать goto.
Правда жизни такова что на уровне системы команд микропроцессора безусловный
переход все равно есть.

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

C

------------------------------
    for (int i = 1; i < 10; i++)
    {
        for (j = 1; j< 10; j++)
        {
            ...
            if (cond(i,j)) goto label;
            ...
        }
    }
label:	;
------------------------------

Имейте в виду что для некоторых языков такой переход будет означать вызов
деструкторов объектов (если они конечно есть) или уборка мусора во внутренних
структурах (и его цена с точки зрения кодогенерации будет довольно высока.
Например:

C++

------------------------------
    for (int i = 1; i < 10; i++)
    {
        A	a;
        for (j = 1; j< 10; j++)
        {
            B  b;
            ...
            if (cond(i,j)) goto label;
            ...
        }
    }
label:	;
------------------------------

будет транслирован в

pseudo-C++
------------------------------
    for (int i = 1; i < 10; i++)
    {
        A	a;
        A::A(&a);
        for (j = 1; j< 10; j++)
        {
            B  b;
            B::B(&b);
            ...
            if (cond(i,j))
            {
                B::~B(&b);
                A::~A(&a);
                goto label;
            }
            ...
            B::~B(&b);
        }
        ...
        A::~A(&a);
    }
label:	;
------------------------------

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

C++

------------------------------
    for (int i = 1; i < 10; i++)
    {
        bool needexit = false;
        for (j = 1; j< 10; j++)
        {
            ...
            if (cond(i,j))
            {
                needexit = true;
                break;
            }
            ...
        }
        if (needexit) break;
        ...
    }
------------------------------

Выносить эту переменную за scope внешнего цикла - личное дело каждого.

  Паралельное исполнение независимого кода

OCCAM

------------------------------
PAR
    SEQ
        BODY_A
    SEQ
        BODY_B

------------------------------

C (OMP)

------------------------------
#pragma omp parallel section
{
    #pragma omp section
        ...		// BODY_A
    #pragma omp section
        ...		// BODY_B
}
------------------------------

CODEGENERATION
-----------------------------------------------------------------------
#pragma omp parallel section		push	offset BODY_B_ADDRESS
{					push	offset BODY_A_ADDRESS
    #pragma omp section		push	2	; количество секций
        ...	// BODY_A	call	RTL_PARALLEL_SECTIONS
    #pragma omp section		add	esp, 12
                    jmp	endlabel
            // BODY_B
}                                   BODY_A_ADDRESS:
                    ...		; BODY_A
                    ret

                    BODY_B_ADDRESS:
                    ...		; BODY_B
                    ret

                    endlabel:
------------------------------------------------------------------------

Собсвенно распаралеливанием управляет RTL (Run Time Library), она знает сколько
процессоров доступно итд. Ей передают адресса секций которые надо выполнить паралельно
и уже она сама запускает код для этих секций. И вдобавок когда управление вернеться
из секций она будет ждать пока последняя секция не закончиться и только тогда вернет
управление в программу, причем в контексте той нити которая просила распаралелиться.


71.1.1.1. УСЛОВНЫЕ ОПЕРАТОРЫ

  Условный оператор

IF condition THEN action_if_condition_true ENDIF

BASIC

-----------------------------
10 	IF A > 0 THEN 30
20 	' fall througth
-----------------------------

C

-----------------------------
    if (a == b)
    {
        ....	// Body
    }

------------------------------

  Полный условный оператор

IF conditon THEN  action_if_condition_true
        ELSE  action_if_condition_false ENDIF

C

-------------------------------
    if (direction = 1)
    {
        i++;	// true body
    } else {
        i--;	// false body
    }
-------------------------------

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

C

-------------------------------
    if (a > 10)  i++;
    if (a > 20)  i+= 2;
    else	     i--;	// else относится к if(a > 20)
                // т.е. к последнему
-------------------------------

ТОDO: проблемы с этим связанные

-------------------------------
if  (time > 21)
    if (weekday == Friday)
           ВремяПитьВодку();
    else
           Надоотдохнуть();
else
    РаботатьЧертиСолнцеЕщеВысоко();
-------------------------------

-------------------------------
if  (time > 21)
    if (weekday == Friday)
           ВремяПитьВодку();
    else
           Надоотдохнуть(); ПожратьБы();
else
    РаботатьЧертиСолнцеЕщеВысоко();
-------------------------------

-------------------------------
if  (time > 21)
    if (weekday == Friday)
           ВремяПитьВодку();
    else
           Надоотдохнуть(); СобратьСумкуНаРаботу();
else
    РаботатьЧертиСолнцеЕщеВысоко();
-------------------------------

-------------------------------
if  (time > 21)
{
    if (weekday == Friday)
    {
           ВремяПитьВодку();
    }
    else
    {
           Надоотдохнуть();
           СобратьСумкуНаРаботу();
    }
}
else
{
    РаботатьЧертиСолнцеЕщеВысоко();
}
-------------------------------

  Условный оператор с инверсной логикой

UNLESS condition THEN action_if_condition_false ENDIF

Perl

------------------------------
    unless (a > b)          # real conditional operator with
    {                       # negative logic
        ....
    }
------------------------------

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

C

-----------------------------
    if (!(a>b))           	// additional operator LOGICAL-NOT (!)
    {                       // but optimizing compiler resolve it.
               ....
    }
-----------------------------

Если хотите можите написать себе макрос и им пользоваться:

C

-----------------------------
#define	unless(x)  if (!(x))
-----------------------------

Собственно компилятор такие вещи будет оптимизировать

    unless(a >= b)
    if (!(a >= b))
    if (a < b)

Противоположные пары условий:

    ==	!=
    >	<=
    >=	<
    <=	>
    <	>=

Соответсвенно есть и полный вариант условного оператора с инверсной
логикой:

Perl

------------------------------
    unless (a > b)
    {
        ....    # if condition false
    } else {
            ....	# if condition true
    }
------------------------------

  Вложенные условные операторы

C

---------------------------------------
if (a == 1)
{
    ...		// a == 1
} else if (a == 4)
{
    ...		// a == 4
} else if (a == 6)
{
    ...		// a == 6
}
----------------------------------------

Некоторые языки используют специальные ключевые слова для замены
сочетания else if.
Например ADA исползует elif
А Алгол-W использует elsif

Можно легко сделать себе макрос в C/C++ для этого

C

-----------------------------
#define	elif(x)	else if(x)
-----------------------------

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

Algol-W

-------------------------------
IF i = 1 THEN
    ....
ELSIF  i  in 2,7 THEN			SELECTION BY LIST
    ....
ELSIF  i  in 3..5 THEN			SELECTION BY RANGE
    ...
ELSIF  (i == 10) THEN
    ...
ELSE
    ...
-------------------------------

Очень интесен с этой точки зрения LISP:

LISP

-------------------------------
    (cond	(CONDITION_1  ACTION_1)
        ....
        (CONDITION_N  ACTION_N))
-------------------------------

LISP проверяет последовательно условия в операторе cond, первое же условие
которое будет true завершает выполнение cond, при этом возвращается ACTION
для этого условия. Если же все условия false, то cond возвращает nil.

  Кодогенерация условного оператора

Conditional operator:
------------------------------------------------------------------------
if (condition)				.... ; condition
{                       	        cmp	ax,0 ; test condition
    ... // body             	jz	cont
}                                     	.... ; body
// cont                         cont:
------------------------------------------------------------------------
if (condition)
{                               	cmp	ax,0	; test condition
    .... // body T          	jz	contE
} else {                        	....	; body T
    .... // body E          	jmp	cont
}                            	contE:
                                    ....	; body E
                cont:
-------------------------------------------------------------------------
if (condition)				....	; condition
{                                       cmp	ax,0	; test condition
    ...   // body T                 jz	contE
} else if (condition2)                   ....	; body T
{                                       jmp	cont
    ...   // body ET        contE:	....	; condition2
} else {                                cmp	ax,0	; test condition
    ...   // body EE                jz	contEE
}					....	; body ET
                    jmp	cont
                contEE:
                    ....	; body EE
                cont:
--------------------------------------------------------------------------
unless (condition)			....	; condition
{                                       cmp	ax,0	; test condition
    ....	// body F               jnz	cont	; OTHER CRITERIA
}                        		.....	; body F
                                cont:
---------------------------------------------------------------------------
unless (condition)                      ....	; condition
{                                       cmp     ax,0	; test condition
     ....	// body F               jnz	contT	; OTHER CRITERIA
} else {                                .....	; body F
        ....	// body T               jmp	cont
}                               contT:
                    .....	; body T
                cont:
----------------------------------------------------------------------------

  Оптимизация условного оператора на уровне дерева

  Оптимизация условного оператора на сравнениях

Арифметический if: значение приходится сравнивать с нулем.
Затем делаем переход в зависимости от результата сравнения
(нас интересует Zero Flag).
На некоторых блатформах это может быть одна инструкция
(Branch по результатам сравнения с нулем).

Логический if который имеет внутри себя в качестве root операцию
сравнения.
Компилятору совершенно не надо castить результат в логический тип
данных, можно сразу использовать флаги, получившиеся в результате
сравнения (в данном случае ZF, так как сравнение на равенство).

То же самое, что в предидущем случае, но используем уже CF
(так как сравнение на неравенство).
А вообще какие флаги использовать зависит от того знаковое или беззнаковое
сравнение и какое именно.

Арифметический if:  операция генерирует флаги (в том числе Zero Flag - который
нужен для арифметического if).
Таким образом конвертация в логический тип и последующее сравнение с нулем
просто не нужны - мы знаем флаги уже непосредственно после операции.

  Оптимизационные Хинты

В современных микропроцессорах во всю используется механизм предсказания
переходов. Неправильно предсказанный переход - это пенальти на перезагрузку
конвеера.

Например архитектура IA-64 имеет следущие варианты условных перходов:

br.cond.sptk		Statically Predicted Taken
br.cond.spnt		Statically Predicted Non-Taken
br.cond.dptk		Dynamically Predicted Taken
br.cond.dpnt		Dynamically Predicted Non-Taken

и еще hinst:

.few			Загружать мало строк кэша
.many			Загружать много строк кэша

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

Например:

for (int i = 1; i < 10; i++)
{
   // девять раз, почти всегда
}

while(a != 0)
{
   // как правило, много раз - это хождения по спискам
}

if (pointer == 0)
{
   // больше всего вероятность, что это проверка указателя на валидность
   // как правило, тело не выполняется
}

if (a == 5)
{
   // как правило, сравнение с конкретным значением
   // выполняется в менее, чем 50% случаев
}

if (a > 5)
{
   // такие вещи более вероятны, чем (a == 5)
}

if (xxx)
{
   // ветка if выполняется чаще, чем else чисто психологически
} else {
}

if (xxx)
{
   // просто простой if как правило не выполняется
}

Соответсвенно компилятор делает форму которая более оптимальна:

Но некоторые компиляторы позволяют прописывать себе указания (hints) в явном виде.
Естественно они являются более преобладающими

-------------------------------
if (foo)
{
}
-------------------------------

Обычный if - неизвестно куда пойдет управление

-------------------------------
if (likely(foo))
{
}
-------------------------------

Указание компилятору - скорее всего foo - будет не равно 0, и тело if выполниться

-------------------------------
if (unlikely(foo))
{
}
-------------------------------

Указание компилятору - скорее всего foo - будет равно 0, и тело if выполняться не будет

GNU C++
-------------------------------
#define likely(x)   __builtin_expect (!!(x), 1)
#define unlikely(x) __builtin_expect (!!(x), 0)
-------------------------------


71.1.1.2. ОПЕРАТОРЫ СЕЛЕКЦИИ

THIS SECTION IS UNDER CONSTRUCTION

FORTRAN

-------------------------------
    GOTO	(1,2,17), I+1
-------------------------------

Переходит на метку или делает pass through.
Вычисляет значение выражения (в данном случае это I+1)
Если выражение равно 1 то переходит к первой метке (1)
Если выражение равно 2 то переходит ко второй метке (2)
Если выражение равно 3 то переходит к третьей метке (17)
итд

Algol-60

-------------------------------
switch	S := L15, L100, L150, L200;
goto S[I];
-------------------------------

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

FORTRAN

-------------------------------
IF (J-2) 10, 20, 30
-------------------------------

Переходит на одну из 3 меток в зависимости от значения выражения
(в данном случае J-2):  >0, ==0, <0

Pascal

-------------------------------
    CASE I OF
        1:	.....		{  Value	  }
        2..15:	....		{  Range	  }
         ELSE:	....		{  None Selected  }
    END;
-------------------------------

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

    autobreak
    fall thought

C

-------------------------------
    switch(i)
    {
    case '1': ...  break;   	     // Need to force exit
    case '2': ...  break;

    case 5:      	// Fall througth     // We can make range this way
    case 6:  ....                        // but it's not so usefull

    default:  ...               	     // None selected
    }
-------------------------------

TODO: расположение Cases

C#

-------------------------------
    switch(a)
    {
    case A:                              // named constant
        ....	// fall throught
    case B:
        ...
        break;
    case C:
        ....
        goto	case B;     	    // goto case construction
    default:
        ...
    }
-------------------------------

D

-------------------------------
    char[] str;
    switch(str)
    {
    case "Hello":
        ...
    case "World":
        ....

    }
-------------------------------

TODO: Кодогенерация

Sparse Mode:

pseudo-C

-------------------------------
    switch(cond)
    {
    case a1:
        ...	// BODY A1
        break;
    case a2:
        ...	// BODY A2
        break;
    case a3:
        ...	// BODY A3
        break;
    default:
        ...	// ELSE BODY
    }
-------------------------------

Dense Mode:

pseudo-C

-------------------------------
    switch(cond)
    {
    case 1:
        ...	// BODY A1
        // fall through
    case 2:
        ...	// BODY A2
        break;
    case 3:
        ...	// BODY A3
        // fall through
    default:
        ...	// ELSE BODY
    }
-------------------------------

Реально генерируемый код в современных компиляторах генерирует
код смеси sparse/dense в зависимости от данных.

  Что мы хотим от оператора селекции?

Обязательно case по спискам и диапазонам.
Обязательно case по строкам

Хотелось бы хотя бы двойные cases

Возможность повтора switch c новым значением
    статическим
    динамическим

TODO: Операторы селекции и VLIW
      Возможность быстро ветвиться среди нескольких направлений (IA-64)
      B 1 bindle - 3 команды условного перехода + переход на следущую команду
      если не одна не сработала.
      Если выполняется несколько переходов сразу - то exception.


71.1.1.3. ЦИКЛЫ

THIS SECTION IS UNDER CONSTRUCTION

  Циклы с предусловием

C

-------------------------------
    while (a != 0)
    {
        ...	// body
    }
-------------------------------

C

-------------------------------
#define	until(x)  while(!(x))

    until (a == 0)
    {
        ...	// body
    }
-------------------------------

бесконечный цикл:

C

-------------------------------
    while(1)
    {
        ...	// body
    }
-------------------------------

макрос на C

C

-------------------------------
#define	forever while(1)
-------------------------------

  Циклы с постусловием

C

-------------------------------
    do
    {
        ...	// body

    } while (a != 0);
-------------------------------

Pascal

-------------------------------
    repeat
        ...	{ body }
    until a = 0;
-------------------------------

C

-------------------------------
#define	until(x)  while(!(x))

    do
    {
        ...	// body
    } until(a == 0)
-------------------------------

  Числовые циклы

Как правило в большинстве языков числовые варианты

Pascal

-------------------------------
    for i:=1 to 15 do begin
        ...	{ body }
    end;

    for j:= 20 downto 1 do begin
        ...	{ body }
    end;
-------------------------------

BASIC

-------------------------------
    FOR K = 1 TO 15 STEP 4
        ...		'body
    NEXT K

    FOR J = 20 TO 1 STEP -1
        ...		'body
    NEXT J
-------------------------------

Perl

-------------------------------
    for (1..15)
    {
        ...	# body, loop variable is $_
    }
-------------------------------

  Полные циклы

FOR (initial; condition; step) BEGIN
    body
ENDFOR

C++

-------------------------------
    for (int i = 1; i < 10; i++)
    {
        ...	// body
    }
-------------------------------

  Управление итерациями внутри тела цикла

C

-------------------------------
    while(1)
    {
        ...
        if (a == 5) break;
        if (a == 7) continue;
    }
-------------------------------

Ruby

-------------------------------
loop do
    i += 1
    break if i > n
end
-------------------------------

Часто удобны макросы:

C

-------------------------------
#define	breakif(x)	if (x) break
#define	continueif(x)	if (x) continue
#define	returnif(x)	if (x) return
-------------------------------

Выход из вложенных циклов

Java

-------------------------------
a:	while()
    {
        while()
        {
            ...
            if (c == 1) break;	// breaking the inner loop
            ...
            if (c == 5) break a;	// break to loop
            ...			// associated with label a
        }
    }
-------------------------------

В Java break на именованую метку осуществляется не то что для цикла,
а вообще для любого scope.

Java

-------------------------------
a:	{
        if (c == 5) break a;
        ...
    }
-------------------------------

  Расширение scope цикла

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

Пример - вычисление простых чисел

Python

-------------------------------
x = y / 2
while x > 1:
    if y % x == 0:
        print y, ' has factor ', x
        break
    x = x - 1
else:
    print y, ' is prime'
-------------------------------

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


71.1.1.3.1. ИТЕРАТОРЫ

THIS SECTION IS UNDER CONSTRUCTION

Циклы по невстроенным объектам

Пишем явно:

C++ (STL)

-------------------------------
list  l;

    ...	// заполняем список

fot (list::const_iterator it = l.begin(); it != l.end(); ++it)
{
    // код для доступа к элементам
}

-------------------------------

  Циклы по встроенным объектам

Многие языки (особенно интерпретируемые) позволяют делать циклы
по встроенным объектам.  В этом случае в роли итератора выступает
предопределенный языком внутренний объект RTL (Run Time Library)

Perl

-------------------------------
    for ((3,7,6,12))  # List
    {
        print $_, "\n"		# print each value
    }

    for (@a)    	# List Variable
    {
        ....
    }
-------------------------------

D

------------------------------------
    foreach(name; args[1..$])
    {
        Stdout.formatln("hello {}", name);
    }
------------------------------------

D имеет синтаксис:
    foreach([index], value; container) {}
        foreach_reverse

  Циклы по итератору

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

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

Языков с чисто компилируемыми итераторами мало.
Как правило используется следующий подход:
    Так как итератору нужен контекст - то используются объекты
    Либо объект должен иметь некоторый предопределенный интерфейс
    Либо его дергают мануально (пример C++ STL)

Пример на интерпретацию:

Ruby

-------------------------------
def repeat(condition)
    yield
    retry if not condition
end

j = 0
repeat (j >= 10) do
    j += 1
    puts	j
end
-------------------------------

  Неявные интерфейсы стоящие за итератором

Собственно С# оператор foreach использует
объект который возвращает интерфейс IEnumerable.
Из которого потом получают интерфейс IEnumerator,
который уже и используется для обхода.

C#

-------------------------------
public interface IEnumerator
{
    bool	MoveNext();
    object  Current { get; }
    void	Reset();
}

public interface IEnumerable
{
    IEnumerator  GetEnumerator();
}

public interface IEnumerator : public IEnumerator, IDisposable
{
    T	Current { get; }
}

public interface IEnumerable : IEnumerable
{
    IEnumerator  GetEnumerator();
}
-------------------------------

C#

-------------------------------
public static IEnumerable Power(int number, int exponent)
{
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
}
-------------------------------

Что генерируется по большому счету?

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


71.1.1.3.2. ПАРАЛЕЛЬНЫЕ ЦИКЛЫ

THIS SECTION IS UNDER CONSTRUCTION

Occam

-------------------------------
PAR I=0 TO 20
    SEQ A[I] := I
-------------------------------

C (OMP)

-------------------------------
    int	i;
    int*	a;	// массив

    #pragma omp parallel for
    for (i = 1; i < 10; i++)
    {
        a[i] = i;
    }
-------------------------------

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

C (OMP)

-------------------------------
    int	i;
    int*	a;	// массив
    int	sum = 0;

    #pragma omp parallel for shared(sum)
    for (i = 1; i < 10; i++)
    {
        sum += a[i];
    }
-------------------------------

Строго говоря есть ограничения на формат параллельного цикла:

for (index = start; index  <   end;   index++	)
               <=         ++index
               >          index--
               >=	      --index
                      index += inc
                      index -= inc
                      index = index + inc
                      index = inc  + index
                      index = index - inc


71.1.2. ПРОЦЕДУРЫ И ФУНКЦИИ

THIS SECTION IS UNDER CONSTRUCTION

Свойства процедуры/функции:

    Имя
    Mangled имя
    Тип  (как правило внутри себя включает типы возращаемого типа и параметров)
    Тип возврашаемого значения
    Параметры
        Тип
        Передача по ссылке, по значению, или по значению с копированием
        Имя  (нужно при передаче параметра по имени)
        Значение параметра по умолчанию
    Специальные модификаторы определяющие свойства
        Тип вызова
            Far
            Near
            Flat
        Конвенция вызова
            C
            Pascal
            Stdcall
            Syscall
            ThisCall
            Interrupt
            Regcall	(есть разные подтипы)
        Специальные модификаторы

  Подпрограммы

Basic

-------------------------------
10	A = 5
20	GOSUB	100
30	A = 10
40	GOSUB	100
50	END
    ...

100	PRINT	A	' Subroutine for print number
110	RETURN
-------------------------------

Главная проблема чистых подпрограмм - отсутствие параметризации
т.е. все параметры передаются через глобальные переменные.

  Процедуры и функции

Абстракция через параметризацию.

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

Чисто процедура - не возращает значение.
Функция - процедура возвращающая значение.

Передача параметров
 --------------------------------------------------------------
Через регистры             	Быстро, но регистров мало, потом их приходится сохранять
Через стек			Медленно
Через глобальные переменные	Медленно и нет реентерабильности.
 --------------------------------------------------------------

 Передача параметров
 --------------------------------------------------------------
По значению
По ссылке
По R-ссылке
 --------------------------------------------------------------

Собственно передавать параметры через R-ссылку безсмысленно, но этот вариант
используется для возврата значений которые нельзя вернуть обычными способами.
(передается по значению, но после возврата
копируется в другое место. Для этого стек должна зачищать вызывающая функция).
Так кстати возвращаются большие структуры по значению из функции:

struct S  F(void)                 	void  F(struct S&  tmp)
{					{
    struct S  s;                    	struct S  s;
    s.xx = xx; 		=>		s.xx = xx;
    ...					...
    return	s;				tmp = s;
}						return;
                    }

Если говорить о передаче по ссылке то есть еще ньюансы:

C#

-------------------------------
public void A(int a);			// By Value
                    // Really by create copy of object

public void A(ref int a);		// By Reference (may be modified)
                    // but parameter must be previously
                    // init

public void A(out int a);		// By Reference
                    // but no initial value need before
                    // call.

-------------------------------

Кодогенерация вызова функции:

Кодогенерация тела функции:

  Указатели на процедуры и функции

THIS SECTION IS UNDER CONSTRUCTION

Указатели на процедуры и функции
    Указатели на простые функции и статичесие методы класса
    Указатели на нестатические методы класса

Типовой синтаксис для указателя на функцию:

    RETURN_TYPE  (* POINTER_TO_FUNCTION) (PARAMS_LIST);

Дополнительные квалификаторы для функций:

    void (* __cdecl PF) (int);	// Конвенция по умолчанию

    void ( __far * PF) (int);	// near/far

Указатель на метод класса:

    RETURN_TYPE (CLASS::*POINTER_TO_CLASS_METHOD) (PARAMS_LIST);

class	A
{
public:
    void	F() {};
};

class  B
{
public:
    virtual void G() {};
};

class  E
{
public:
    virtual void X() {};
};

class  F : public B, public E
{
};

class C : virtual public A, virtual public B
{
public:
    virtual void H() {};
};

class I
{
public:
    void	T(){};
};

class  D : virtual public A, virtual public I
{
};

#include

void __cdecl main()
{
    void (A::*pa)() = A::F;
    void (B::*pb)() = B::G;
    void (F::*pf)() = F::G;
    void (C::*pc)() = C::H;
    void (D::*pd)() = D::T;

    printf("Sizeof(pa) = %d\n", sizeof(pa));
    printf("Sizeof(pb) = %d\n", sizeof(pb));
    printf("Sizeof(pf) = %d\n", sizeof(pf));
    printf("Sizeof(pc) = %d\n", sizeof(pc));
    printf("Sizeof(pd) = %d\n", sizeof(pd));

}

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

Sizeof(pa) = 4
Sizeof(pb) = 4
Sizeof(pf) = 8
Sizeof(pc) = 12
Sizeof(pd) = 12

  Замыкания

THIS SECTION IS UNDER CONSTRUCTION

Perl

-------------------------------
    sub	say
    {
        my  $salute = shift;
        my  $newfunc = sub
        {
            my $target = shift;
            print	"$salute, $target!\n";
        };
        return	$newfunc;
    }

    $f = say("howdy");
    $g = say("greetings");

    $f->("word");		# print 'howdy, word!\n'
    $g->("earthlings");	# print 'greetings, earthlings!\n'
-------------------------------

Например в C++ реализуется через функторы.


71.1.2.1. ФУНКЦИИ С ПЕРЕМЕННЫМ ЧИСЛОМ АРГУМЕНТОВ

THIS SECTION IS UNDER CONSTRUCTION


71.1.3. ТИПЫ ДАННЫХ И КОНСТАНТЫ

THIS SECTION IS UNDER CONSTRUCTION

Типы данных
    Целочисленные
    Floating Point (и Fixed Point)
    Символьные
    Строковые
    итд

  Целочисленные типы данных

Практически всегда в современных языках - представляют целые в машинном
формате, то есть практически всегда - дополнительный код до 2

Параметры целочисленных типов данных:
    - Размер  (как правило в байтах, для старых платформ есть ньюансы
    - Выравнивание (как правило следует из размера)
    - Signed/Unsigned
    - Endian

В одних языках программирования размеры типов фиксированы.
А в других языках нет (зависит от модели памяти).

MS-FORTRAN

-------------------------------
    INTEGER * 4	MYVAR;
    INTEGER * 2	MYVAR2;
-------------------------------

Рассмотрим целочисленные типы данных для C/C++

Тип		Signed?         Size (bytes)    Комментарии
char		   S/U/-	1		Может быть signed или unsigned
signed char	   S		1
unsigned char	   U		1
short		   S		2		тоже что signed short
signed short	   S		2
unsigned short	   U		2
int		   S		2/4		тоже что signed int
signed int	   S		2/4
unsigned int	   U		2/4
long		   S		4/8		тоже что signed long
signed long	   S		4/8
unsigned long	   U		4/8
long long	   S		8+		тоже что signed long long
signed long long   S		8+
unsigned long long U		8+

Поэтому для таких языков делаются специальные заголовочные файлы которые
определяют типы данных для конкретного таржета конкретной платформы.
Например для C99 это stdint.h

    - intXX_t/uintXX_t  - строгое соответсвие по размеру

int8_t 	  int16_t     int32_t     int64_t
uint8_t   uint16_t    uint32_t    uint64_t

    - int_leastXX_t/unit_leastXX_t

Не на всех платформах есть аппаратная реализация например для 16-байтовых целых
least - означает что это целый тип той же знаковости, но содержит больше битов

int_least8_t
uint_least8_t

    - int_fastXX_t/int_fastXX_t

fast - наиболее быстрый тип с разрядностью не меньше чем задано

int_fast8_t
uint_fast8_t

    - intmax_t/uintmax_t

max - тип данных максимального размера поддерживаемый платформой

    - intptr_t/uintptr_t

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

А как быть с константами?  Ведь типы не встоены в язык а лежат в RTL
Макросы:
INT8_C(x)		UINT8_C(x)
INT16_C(x)		UINT16_C(x)
INT32_C(x)		UINT32_C(x)
INT64_C(x)		UINT32_C(x)
INT_LEAST8_C(x)		UINT_LEAST8_C(x)
INT_LEAST16_C(x)	UINT_LEAST16_C(x)
INT_LEAST32_C(x)	UINT_LEAST32_C(x)
INT_LEAST64_C(x)	UINT_LEAST64_C(x)
INT_FAST8_C(x)		UINT_FAST8_C(x)
INT_FAST16_C(x)		UINT_FAST16_C(x)
INT_FAST32_C(x)		UINT_FAST32_C(x)
INT_FAST64_C(x)		UINT_FAST64_C(x)

Реализация

#define	INT64C_(X)	X ## ULL

Endian:

PGL

-------------------------------
    dword little	led;
    word  big	bew;
    dword native	led2;
-------------------------------

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

PGL

-------------------------------
    dword litle <- led;
-------------------------------

  Целочисленные константы

Параметры целочисленные констант:
    - Тип
    - Система счисления

Обычные в десятичной системе:

    12
    -100

С/C++: суффиксы определяющие тип

    12	это int
    12u	это unsigned int
    12l	это long
    12ul	это unsigned long
    12ll	это long long
    12ull	это unsigned long long

    012	octal = 10
    0xc	hexdecimal = 12

BASIC: префиксы определяющие тип

    12	decimal
    &O14	octal
    &HC	hexdecimal
    &B1100	binary

ASM:

    1101b	binary
    12	decinal
    123h	hexdecimal
    0c21h	hexdecimal

Mathematica:
    основание^^число

    12^^3ba

основание записывают десятичными цифрами (от 2 до 36)
а число уже понятно в соответсвующей системе счисления.

MS-Fortran:
    [знак][основание] # число

    если основание пропущено то считаем его равным 16
    обычные десятичне не содержат #

    -16#abcd
    -#3FF

VHDL:

    основание#число#

    2#1101001#
    16#DE#
    S2E2		целое число в экспотенцианой форме

Задание системы счистления по умолчанию:

Asm

    .RADIX	16	задает систему счистления по умолчанию

  Аттрибуты целочисленного типа данных

    Либо встроены в язык (типа ADA)
    либо возложены на RTL

Собственно рефлексия - возможность получить информацию о типе данных
на compile и run-time.

Вариант для C:

Описано в limits.h

    CHAR_BIT	число битов в байте

    (TYPE)_MAX	максимальное значение
    (TYPE)_MIN	минимальное значение (только для signed)

Типовой набор выглядит так:

#define	CHAR_BIT	8
#define	SCHAR_MIN	(-128)
#define	SCHAR_MAX	127
#define	UCHAR_MAX	0xff

#define	SHRT_MIN	(-32768)
#define	SHRT_MAX	32767
#define	USHRT_MAX	0xffff

Соответсвенно C99 добавляет к этому всякие:

    INT8_MIN
    INT8_MAX
    INT_LEAST16_MAX
    INT_FAST32_MIN

итд

TODO: Для С/C++

Целочисленные типы большого размера

Logo

-------------------------------
    SETPRECESION	50
-------------------------------

В данном примере мы установили точность по умолчанию для целых
чисел 50 знаков.

  Символьные типы данных

Собственно по большому счету символьные типы данных - это теже самые
целые числа  (как правило unsigned, но для C в свое время можно было задавать
опциями компилятора является ли char signed или unsinged).

тип		размер		Комментарии
char		1
wchar           2/4             зависит от платформы
dchar		4		язык D

Можно посмотреть секцию 70.2.3. ПРЕДСТАВЛЕНИЕ СИМВОЛОВ.
Там детально описываются как представляются символы.

  Символьные константы

    'c'		character

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

Символы которые подставляются

    \a		BELL
    \b	        BS
    \f		FF
    \n		LF
    \r		CR
    \t		TAB (HT)
    \v		vt
    \\		\
    \"		"
    \'		'
    \?		?
    \nnn		Octal value (n = 0..7)
    \xnn		Hexdecimal value (n = 0..f)
    \unnnn  	Unicode character (16-bit)
    \Unnnnnnnn	Unicode character (32-bit)
    \N{name}	Unicode character with specified name
            example:  \N{euro sign} \u20AC \U000020AC
    \сX		X = A..Z, control character
            example:  EOF (26) is CTRL-Z i.e. \cZ

  Логический тип данных

тип	размер	комментарий
bool	1/2/4	зависит от платформы

И как правило имеем в языках две предопределенные константы:

    true
    false

  Типы данных с плавающей точкой

тип		размер	комментарий
float		4/8
double		8/16
long double	8/16
double double	16/32

  Константы с плавающей точкой

обычные:

    0.12
    1.24

в экспотенциальной форме:

    1.35e-12
    -7.24e10

типизация:

    1.24f		type float
    -1.2e+7l	type long double

в шестнадцитиричной форме:

    0x1.5p10
    0x1p01

комплексные числа (в некоторых языках)

    3+4j
    3.0+4.0j
    3J

  Аттрибуты типа данных с плавающей точкой

На примере языка D

    TYPE.infinity
    TYPE.nan
    TYPE.dig
    TYPE.epsilon
    TYPE.mant_dig
    TYPE.max_10_exp
    TYPE.max_exp
    TYPE.min_10_exp
    TYPE.min_exp
    TYPE.max
    TYPE.min

  Векторные типы данных

THIS SECTION IS UNDER CONSTRUCTION

В настоящее время очень много SIMD hardware и некоторые языки программирования
расширяют операции также для работы с векторами:

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

GCC 4

    typedef int v4si __attribute__((vector_size(16)));
                    // vector size = 16 bytes
    v4si	a, b, c;

    a = b + c;

  Сложные типы данных

  Типы данных с неинициализированными значениями

В принципе одна из интересных реализаций это C#.
Типы с неиницилизированными значениями объявляются как TYPE?

Значения по умолчанию

--------------------------------
Ссылочные типы	ref	null
Типы значений	numeric	0
        char	'\0'
        bool	false
--------------------------------

C#

int?	x = 5;
int?	y = 10;

bool b = x < y;

            // реально кодогенерируется в:

bool b = (x.HasValue && y.HasValue) ? (x.Value < y.Value) : false;

Реализация базируется на:

public struct Nullable where T : struct
{
    public T Value { get; }
    public bool HasValue { get; }
    public T GetValueOrDefault();
    public T GetValueOrDefault(T defaultValue);
}

Интересно что есть операция ?? смысл которой сводится к следущему:
Если значение по умолчанию, то заменить ее на указанное, если нет
то оставить как есть.

C#

int?	x;
int?	y;
int?	z;

y = x ?? 5;	// y = 5 (так как у х значение по умолчанию)
z = y ?? 7;	// z = 5 (так как у y есть реальное значение)

  Строковые типы данных

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

Прочтите секцию 70.2.6. СТРОКИ для того что бы представлять методы
их хранения.

  Строковые константы

    - Ширина символов  (простые, unicode, итд)
    - Наличие или отсутсвие подстановки специальных символов
    - Singleline или Multiline

    "string"        C/C++  byte string (char*)
    L"string"	C/C++  unicode string (wchar_t*)

Есть неудобство с подставление символов:

Что бы написать в строке
    "C:\Windows\myfile"
надо писать:
    "C:\\Windows\\myfile"

Ruby	".."	строка с подстановками символов
    '..'	строка без постановок символов

Ruby	%q[...]			[] - separators %q treats as '
    %Q[...]			[] - separators %Q treats as "

    str = <

  Коллекции

    Массивы
    Списки
    Hashes

  Более сложные типы

    Файлы
    Интерфейсы (к БД)


71.1.4. ОПЕРАЦИИ

THIS SECTION IS UNDER CONSTRUCTION

  Арность операций

Какие вообще бывают операции? Обзор

Примеры:

- X		Unary prefix		(operation) (operand)
X ++		Unary postfix		(operand) (operation)
X + Y		Binary infix		(operand-R) (operation) (operand-L)
(A)? B: C       Ternary

Пример дерева разбора для унарной операции:

Пример дерева разбора для бинарной операции:

Краткий список основных операций:
--------------------------------------------------------------------------
Имя	Тип	Ассоциативность	Описание				Язык
+	bin	все равно(L)	l + r		Сложение                C
-	bin	левая		l - r		Вычитание               C
*	bin	все равно(L)	l mul r		Умножение               C
/	bin	левая		l div r		Деление (цел)           C
%	bin	левая		l mod r		Остаток от деления      C
+	unr	префикс		+ r		Унарный плюс		C
-	unr	префикс		- r		Унарный минус		C
++	unr	префикс		r = r + 1, r	Преинкремент		C
++	unr	постфикс	return r, r = r + 1 Постинкремент	C
--	unr	префикс		r = r - 1, r	Предекремент		С
--	unr	пофтфикс	return r, r = r - 1 Постдекремент	С
&	bin	все равно(L)	bitwize AND
|	bin	все равно(L)	bitwize OR
~	unr	префикс		bitwize NOT
^	bin	все равно(L)	bitwize	XOR
!	unr	префикс		logical NOT
&&	bin	все равно(L)	logical AND
||	bin	все равно(L)	logical OR
<<	bin			Shift Left  Logical
>>	bin			Shift Right Logical
>>>	bin			Shift Right Arithmetic         		Java
==	bin	Logical compare equal
!=	bin	Logical compare non-equal	(<> , ><)
>	bin	Logical compare gretaer
<	bin	Logical compare less
>=	bin	Logical compare greater-equal
<=	bin	Logical compare less-equal
**	bin	Expotencial					SmallTalk
?	bin	Minimum                                         GNU C
?:	bin	if l !=0 then l, else r
//	bin	divide (return integer part, truncate -infin)	SmallTalk
\\	bin	divide (return remainder)			SmallTalk
=:=     bin	тождественное равенство
=/=	bin	тождественное неравенство
&	unr	Reduce all-bits bitwize AND			Verilog
|	unr	Reduce all-bits bitwize OR			Verilog
^	unr	Reduce all-bits bitwize XOR			Verilog
~&	unr	Reduce all-bits bitwize AND-NOT			Verilog
~|	unr	Reduce all-bits bitwize OR-NOT			Verilog
~^	unr	Reduce all-bits bitwize XOR-NOT			Verilog
--------------------------------------------------------------------------

  Ассоциативность операций

Бинарные инфиксные операции бывают левоассоциативные и правоассоциативные.

Рассмотрим последовательность операций:

    l OP m OP r

Левоассоциативные операции:   l OP m OP r = (l OP m) OP r
То есть средний операнд относится к левой операции:
Группируются с помощью скобок слева направо.

Правоассоциативные операции:  l OP m OP r = l OP (m OP r)
Средний операндд относиться к правой операции
Группируются с помощью скобок справа нелево.

Пример левоассоциативной операции:

Пример правоассоциатиной операции:

C Этой точки зрения интересен пролог:
У него задается ассоциативность операции:

    xfx	xfy	yfx		для Binary
    fx	fy			для Unary Prefix
    xf	yf			для Unary Postfix

x означает - что приоритет х строго выше чем приоритет операции
y означает - что приоритет y больше или равен приоритету операции:

Например для вычитания

    a - b - c

    (a - b) - c		имеет тип  yfx

  Оптимизация константных подвыражений

  Бинарные операции

  Сложение

Ассоциативно.

a + b = b + a

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

И оптимизация константных подвыражений

  Вычитание

Левая ассоциативность.
Порядок вычисления операндов не определен.

  Умножение

Как правило делают левоассоциативным, что бы иметь тот же
приоритет операции, что и деление и остаток от деления.
Порядок вычисления операндов не определен.

  Деление

Левоассоциативно.
Порядок вычисления операндов не определен.

  Остаток от деления

Левоассоциативно.
Порядок вычисления операндов не определен.

  Сдвиги

Оптимизация:

1) Объединение сдвигов в одну сторону.

    A >> B >> C  =  A >> (B + C)

2) Нельзя объединять сдвиги в разные стороны:

    A >> B << B  != A

// TODO: Сюда еще и Rotates

  Сравнения

  Бинарные битовые операции

  Бинарные логические операции

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

Потому что:

    A && B

Если мы уже вычислили A то имеем следущие варианты:
Если A == 0
    (A && B) = (0 && B) = 0  то есть нам уже не надо вычислять B
                     результат мы знаем
Если A == 0
    (A && B) = (1 && B) = B  то есть нам надо вычислять B

    A || B

Если мы уже вычислили A то имеем следущие варианты:
Если A == 0
    (A || B) = (0 || B) = B	то есть нам надо вычислять B, он и будет результат
Если A == 1
    (A || B) = (1 || B) = 1 результат мы знаем

  Максимум/Минимум

    A ?> B	максимум
    A ?< B  минимум

    A ?> B =
        if (A >  B) return A;
        else	    return B;

    A ?< B =
        if (A <  B)  return A;
        else	     return B;

  Унарные операции

  Унарный плюс

  Унарный минус

  Унарный NOT

  Унарный логический NOT

  Унарная инкрементация/декрементация

  Population count

  Операции свертки

  Тернаные операции

  Условная операция

     cond ? A : B =
        if cond then return A;
        else	     return B;

Ассоциативность правая:

    a ? b ? c : d ? e : f : g =
    a ? ( b ? c : (d ? e : f) ) : g

  Операция принадлежности диапазону

Всегда хотел иметь удобную операцию принадлежности диапазону

соответсвенно включая или не включая конец диапазона

    A in (MIN .. MAX)
    A in [MIN .. MAX]
    A in (MIN .. MAX]
    A in [MIN .. MAX)

THIS SECTION IS UNDER CONSTRUCTION

  Приорететы операций

Рассмотрим приоритеты операций в C
------------------------------------------------------
16	[]				левый
    ()
    .member
    ->member
    ++	(postfix)
    --	(postfix)
------------------------------------------------------
15	sizeof				правый
    ++	(prefix)
    --	(prefix)
    &	(unary)
    *	(unary)
    +	(unary)
    -	(unary)
    ~	(unary)
    !
------------------------------------------------------
14	(TYPE)				правый
------------------------------------------------------
13	*				левый
    /
    %
------------------------------------------------------
12	+				левый
    -
------------------------------------------------------
11	<<				левый
    >>
------------------------------------------------------
10	< 				левый
    <=
    >
    >=
------------------------------------------------------
9	==				левый
    !=
------------------------------------------------------
8	&				левый
------------------------------------------------------
7	^				левый
------------------------------------------------------
6	|				левый
------------------------------------------------------
5	&&				левый
------------------------------------------------------
4	||				левый
------------------------------------------------------
3	?:				правый
------------------------------------------------------
2	=                               правый
    *=
    /=
    %=
    +=
    -=
    <<=
    >>=
    &=
    ^=
    |=
------------------------------------------------------
1	,				левый
------------------------------------------------------

Приорететы операций в пролог
------------------------------------------------------
300	xfx	mod
------------------------------------------------------
400	yfx	*  / div
------------------------------------------------------
500	fx	+  -  not
------------------------------------------------------
500	yfx	+  -
------------------------------------------------------
700	xfx	=  is <  >  =  >= <=  =/= \==  =:=
------------------------------------------------------
1000	xfy	,
------------------------------------------------------
1100	xfy	;
------------------------------------------------------
1200	fx	:-    ?-
------------------------------------------------------
1200	xfx	':-'
------------------------------------------------------

  Пропоргация типов

THIS SECTION IS UNDER CONSTRUCTION

  Деревья выражений

THIS SECTION IS UNDER CONSTRUCTION

  Раскраска регистров нетрезвыми красочками

THIS SECTION IS UNDER CONSTRUCTION


71.1.4.1. ПЕРЕГРУЗКА ОПЕРАЦИЙ

THIS SECTION IS UNDER CONSTRUCTION

  Специальная семантика

    x -> y

означает:

    (x.operator->() ) -> y

  Нарушение семантики при перезагрузки

    x && y

собственно означает

    (x)? y : false		// y вычисляется только если x - true

а после перегрузки получаем

    x.operator&&(y)		// y вычисляется всегда

  Сравнения

C++ как правильно с наименьшими усилиями делать арифметический тип данных.
Достаточно одного строгово сравнения, все остальные получаются из него:

пусть есть	    A > B
    A < B    =  B > A
    A <= B   =  !(A > B)
    A >= B   =  !(B > A)
    A == B	 =  !(A > B) || !(B > A)
    A != B   =  (A > B) || (B > A)


71.1.5. ОБЪЕКТЫ

THIS SECTION IS UNDER CONSTRUCTION

Объекты - инкапсуляция кода с данными.

На уровне класса.
Следущий уровень - инкапсуляция кода у конкретного экземпляра класса

Собственно языки можно поделить на 2 группы
    С поддержкой множественного наследования
    Без поддержки множественного наследования

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

  Специальные методы класса

Специальные методы класса
    Конструктор
    Деструктор
    Конструктор по умолчанию
    Копирующий конструктор
    Оператор присваивания

  Наследование

Виртуальные функции
Множественное наследование
Брилиантовое наследование
Виртуальное наследование


71.1.5.1. ПРЕОБРАЗОВАНИЯ ТИПОВ

THIS SECTION IS UNDER CONSTRUCTION

  Upcase

  Downcast

  Crosscast


71.1.6. МОДУЛИ

THIS SECTION IS UNDER CONSTRUCTION

Некоторые языки предусматривают модульность.
Другие просто разрешают ссылки при линковке.


71.1.7. ИСКЛЮЧЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

Языковые
Системные

Как это работает?

try
catch
catch
else
finally

_leave


71.1.8. МАКРОКОНСТРУКЦИИ

THIS SECTION IS UNDER CONSTRUCTION

Макросы
    на уровне символов
    на уровне лексем

Использование макросов для генерации макросов


71.1.9. ПРОСТРАНСТВА ИМЕН

THIS SECTION IS UNDER CONSTRUCTION

Обычные
Классовые

Неименованное пространство имен


71.1.10. ШАБЛОНЫ

THIS SECTION IS UNDER CONSTRUCTION

Шаблоны - параметризированные типы

Ограниченый типовой полиморфизм
    Накладывается конктракт

Неограниченный типовой полиморфизм
    Нет никакой зависимости

Все начиналось с языка ADA

TODO:

Явное инстансирование шаблонов

  C++

Типы шаблонов
    Шаблоны функций
    Шаблоны классов
    Шаблоны функций членов-класса
    Шаблоны вложенных классов

Параметры шаблонов
    Типы
    Целочисленные константы
    Другие шаблоны
    Указатели
    Функции

  Шаблоны функций

C++

    template <class T> void swap(T& a, T&b)

функции перебивают шаблоны

  Шаблоны классов

типы шаблонов класса
    первичный шаблон класса
    частичная специализация шаблона класса
    полная специализация шаблона класса

C++

    template <class T> class vector
    {
        ...
    };

  Шаблоны функций членов класса

C++

    class	A
    {
        template <class T> void method(T x);
        ...
    };

  Шаблоны вложенных классов

C++

    class	A
    {
        template <class T> class MemberClassTemplate
        {
            ...
        }
    }

  Java

Java	- обобщения работают только с объектными типами

Java
    обобщенные методы (в том числе и static)
    обобщенные конструкторы
    обобщенные интерфейсы
        interface MinMax>

Java

class Gen<T>
{
    T	ob;

    Gen(T o)
    {
        ob = o;
    }

    T getob()
    {
        return	ob;
    }
}

Gen<Integer> t = new Gen<Integer>(1);

  Синтаксис аргументов шаблона

обычные аргументы:

    <T>
    <T extends SUPERCLASS>	ограничение сверху (суперкласс и его потомки)

    <T extends SUPERCLASS & INTERFACE>

Шаблонные аргументы:

    <?>			неизвестный аргумент
    <? extends SUPERCLASS>
    <? super   SUBCLASS>	нижняя граница (только классы которые являются
                предками SUBCLASS, не включая сам SUBCLASS

Java

boolean	sameAvg(Stats<?> ob)
{
    if (average() == ob.average())
        return	true;
    return	false;
}

  C#

C# поддерживает:

    Обобщенные классы/струкутры
    Обобщенные методы
    Обобщенные делегаты
    Обобщенные интерфейсы

ограничения:

class NAME<T> where T : SUPERCLASS
          where T : struct			// value type
          where T : class			// reference type
          where T : new()			// constructor w/o params

class Gen<T> where T : SUPERCLASS, IFACE, new()
{
    ...
}

public static bool CopyInsert<T>(T e, uint indx)


71.1.11. RTTI (RUN TIME TYPE INFORMATION)

THIS SECTION IS UNDER CONSTRUCTION

Зачем нужен RTTI?
    сравнение типов

    динамическое приведение типов
        RTTI позволяет делать такую вещь как crosscast

Как он реализуется


71.2. ДЕКЛАРАТИВНЫЕ ЯЗЫКИ ПРОГРАММИРОВАНИЯ

THIS SECTION IS UNDER CONSTRUCTION

    PROLOG

Задача - выполнить цель
База знаний

Показать обход в поисках решения

    P :- Q, R.

    P :- Q; R.		P :- Q.
                P :- R.

Prolog

-------------------------------
    gcd(X,X,X).
    gcd(X,Y,Z) :-
            X < Y,
            T  is  Y - X,
            gcd(X, T< Z).
    gcd(X,Y,Z) :-
            Y < X,
            gcd(Y, X, Z).

-------------------------------

Отсечение:

Prolog

-------------------------------
    max(X,Y,Z) :-  X >= Y, !.
    max(X,Y,Y).
-------------------------------


71.3. ЯЗЫКИ УПРАВЛЯЕМЫЕ ПОТОКОМ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

Языки управляемые потоком данных - команда выполняется когда котовы ее операнды.

    LISP

Вся программа является гигантским деревом, которое обходится и выполняются ее ветки
(в некоторых случаях генерируются новые ветки).

Детально показать


71.4. ЯЗЫКИ ОПИСАНИЯ ОБОРУДОВАНИЯ

THIS SECTION IS UNDER CONSTRUCTION

    VHDL
    Verilog

Поток управления по набору условий.

Обязательно типы значений
    + таблицы для AND и OR

Обязательно синтез для основных конструкций


71.5. ПРОБЛЕМНО-ОРИЕНТИРОВАННЫЕ ЯЗЫКИ СВУ

THIS SECTION IS UNDER CONSTRUCTION

Языки  СВУ - языки Сверх-высокого уровня, ориентированные
на проблематику в конкретной области.

Типовые примеры: пакеты для математических вычислений

    Mathematica
    Mapple
    MatLAB
    MathCAD


71.6. ABI (APPLICATION BINARY INTERFACE)

THIS SECTION IS UNDER CONSTRUCTION

    Calling conventions
    Name mangling


71.6.1. КОНВЕНЦИИ ВЫЗОВОВ

THIS SECTION IS UNDER CONSTRUCTION

  Передача параметров через стек

Порядок в котором параметры заталкиваются в stack

  Передача параметров через регистры

  Передача структуры по значению

  Стековый фрейм

  Пролог

  Эпилог

  Возврат значения

  Возврат структуры

  Возврат из подпрограммы

Кто за собой чистит stack.


70.50. ТЕОРИЯ ВЫЧИСЛЕНИЙ

THIS SECTION IS UNDER CONSTRUCTION


70.50.1. ГРАММАТИКИ

THIS SECTION IS UNDER CONSTRUCTION

Def
===
Грамматика - совокупность (Vt, Vn, P, S), где

Vt - алфавит терминальных символов
Vn - алфавит нетерминальных символов
P  - множество правил  a -> b

Пример:

Язык:
    { x{n}y{n} | n > 0 }

Грамматика:
    G = ({x,y}, {S}, P, S)

Множество правил P:
    P = { S -> xSy ,  S -> xy }

    { x{m}y{n} | m,n >= 0 }

    G = ({x, Y}, {S, B}, P, S)

    P:
        S -> xS
        S -> yB
        S -> x
        S -> y
        B -> yB
        B -> y
        S -> e

Пример вывода предложения: xxyyy

    S => xS => xxS => xxyB => xxyyB => xxyyy

Строго говоря для одного языка могут быть разные грамматики
например:

    { x{m}y{n} | m,n > = 0 }

    G = ({x,y}, {S, X, Y}, P, S)

    P:
        S -> XY
        X -> xX
        X -> e
        Y -> yY
        Y -> e

    { a{n}b{m}c{p} | n,m,p > 0 }

    S -> aA
    A -> aA
    A -> bB
    B -> bB
    B -> cC
    B -> c
    C -> cC
    C -> c

    { a{n}b{m}c{m}d{n} | n,m > 0 }

    S -> aSd
    S -> aTd
    T -> bTc
    T -> bc

    { a{n}b{n}c{n} | n > 0 }

    S  -> aSBC
    S  -> aBC
    aB -> ab
    bB -> bb
    CB -> BC
    bC -> bc
    cC -> cc

Праволинейная грамматика:
    в правой части всех правил нетерминальный символ всегда находистся справо

        X -> xX

Леволинейная грамматика:
    в правой части всех правил нетерминальный символ всегда находится слева

        S -> Sy
        S -> Bx
        S -> x
        S -> y
        B -> Bx
        B -> x
        S -> e

Праволинейный и леволинейные грамматики называются регулярными.

Грамматики имеющие и леволинейные и праволинейные продукции не являются
регулярными.

Прямая рекурсия

    A -> Ab
    B -> cB
    C -> dCf

Непрямая левая рекурсия
    A -> Bc
    B -> Cd
    C -> Ae

Если грамматика не содержит средней рекурсии, то она регулярная.

  Типы грамматик по Хомскому

    3 тип - регулярные
    2 тип - контекстно-свободные
    1 тип - контекстно-зависимые
        (линейно-ограниченные)
    0 тип - рекурсивно-перечисляемые
        (экивалентно определению грамматики)

Грамматики 3 типа как правило используются для лексического анализа
Грамматики 2 типа как правило используюься для синтаксического анализа

Контекстно-зависимые

    a -> b
    |a| <= |b|
    модуль здесь - это количество символов которое может порадить.

Если в левой части продукции только один нетерминал - то это грамматика 2 типа.

Нормальная форма Хомского

использует только продукции следущих видов:

    A -> BC
    A -> a
    A -> e

Нормальная форма Грейнбаха

использует только продукции вида

    A -> aV1V2V3...Vk	(k >= 0)

пример
    S -> aAB
    A -> aA | bB | b
    B -> b


70.50.2. АВТОМАТЫ

THIS SECTION IS UNDER CONSTRUCTION

Def
====

Автомат - совокупность	M = (K, Z, b, S, F) где
    K - множество состояний
    Z - алфавит
    b - множество переходов
    S - начальное состояние (S принадлежит K)
    F - множество конечных состояний (F принадлежит K)

Детерменированность:

FA:

PDA:


70.50.3. НФБН

THIS SECTION IS UNDER CONSTRUCTION

НФБН (BNNF)

    Нормальная форма


70.50.3. ЛЕКСИЧЕСКИЙ АНАЛИЗ

THIS SECTION IS UNDER CONSTRUCTION


70.50.4. СИНТАКСИЧЕСКИЙ АНАЛИЗ

THIS SECTION IS UNDER CONSTRUCTION

    S    -> EXP
    EXP  -> TERM
    EXP  -> EXP + TERM
    EXP  -> EXP - TERM
    TERM -> FACT
    TERM -> TERM * FACT
    TERM -> TERM / FACT
    FACT -> - FACT
    FACT -> VAR:ID
    FACT -> NUM:NUM
    FACT -> ( EXP )


72.1. СЖАТИЕ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

Зачем это надо?

Идея:  	Часто использующие символы - кодируем короче
    Редко используемые символы - длиннее

THIS SECTION IS UNDER CONSTRUCTION

        Без потерь
        /	\
    Частотное       Словарное
    /        \
  Статическое  Адаптивное

Статическое сжатие:

Адаптивное сжатие:

Адаптивная декомпрессия:

Частотное сжатие:
    SF/HA
    Арифметическое кодирование

Словарное сжатие:
    RLE
    группа LZ алгоритмов (LZ77,LZ78,LZW)

    Важно правильно преобразовывать файлы (EXE call/jumps)
    (Препроцессинг)


72.1.1. ТЕОРИЯ ИНФОРМАЦИИ

  Мера информации Хартли

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

    I = log{2}(n)	бит

пусть у нас есть слово состоящее из m символов, тогда для него:

    Число состояний = n^m

    I = log{2} (n^m) = m * log{2} (n)

График зависимости числа необходимых бит от числа состояний

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

    I = log{3}(n)	трит
и даже:
    I = ln(n)	нит

    I = log{10}(n)	дит

    1 нит = 1.44269 бит
    1 дит = 3.32193 бит - ее еще называют хартли

  Энтропия Шенона

Клод Шенон:

Знание (информация) - это уменьшение неопределености.

Информационная энтропия расчитывается как:

где Pk - вероятность появления того или другово значения у символа.

Пример график зависимости энтропии для бита с различной частотой
появления 1 (от 0 до 1).

Понятно что:
    Энтропия равна 0, если вероятность символа равна 1
    Символ с вероятностью 0 не влияет на энтропию
    Максимальная энтропия равная 1 достигается если все символы
    равновероятны  (имеет место быть в случае абсолютно случайных данных).

Что такое сжатие:
    Данные имеют информационную энтропию отличную от 1

    Максимально возможное сжатие (без потерь) C = 1 - H(data)
    т.e если данные 100% предсказаны то C = 1 - 0 = 1 (100%)
    сжимать их не надо мы их и так знаем априорно

    С другой стороны для абсолютно случайных данных
    (понятное дело бесконечной длинны)
    С = 1 -  1 = 0, то есть мы их никогда не сожмем.


72.1.2. СЛОВАРНОЕ СЖАТИЕ

THIS SECTION IS UNDER CONSTRUCTION

  RLE

RLE (Run Length encoding):

  LZ

группа LZ алгоритмов (LZ77,LZ78,LZW)

  LZ77

  LZSS

  LZ78

  LZW


72.1.3. ЧАСТОТНОЕ СЖАТИЕ

THIS SECTION IS UNDER CONSTRUCTION

Частота букв в Англиском языке:

Азбука Морзе:

    3 cимвола:
        'o'	точка
        '-'	тире
            ' '	пробел

    ---------------------------------
    A	o-	|  А	o-
    B	-ooo    |  Б    -ooo
    C       -o-o    |  В    o--
    D       -oo     |  Г    --o
    E       o       |  Д    -oo
    F       oo-o    |  Е    o
    G       --o     |  Ж    ooo-
    H       oooo    |  З    --oo
    I       oo      |  И    oo
    J       o---    |  К    -o-
    K       -o-     |  Л    o-oo
    L       o-oo    |  М    --
    M       --      |  Н    -o
    N       -o      |  О    ---
    O       ---     |  П    o--o
    P       o--o    |  Р    o-o
    Q       --o-    |  С    ooo
    R       o-o     |  Т    -
    S       ooo     |  У    oo-
    T       -       |  Ф    oo-o
    U       oo-     |  Х    oooo
    V       ooo-    |  Ц    -o-o
    W       o--     |  Ч    ---o
    X       -oo-    |  Ш    ----
    Y       -o--    |  Щ    --o-
    Z       --oo    |  Ы    -o--
    0       -----   |  ЬЪ   -oo-
    1       o----   |  Ю    oo--
    2       oo---   |  Я    o-o-
    3       ooo--   |
    4       oooo-   |
    5       ooooo   |
    6       -oooo   |
    7       --ooo   |
    8       ---oo   |
    9       ----o   |
    ---------------------------------

  SF

SF (Shannon-Fano)

  HA

HA (Haffman)

В отличии от SF - дерево в HA строится снизу. Таким образом достигается
большая степень сжатия.

  Арифметическое кодирование

Арифметическое кодирование - типа как непрерывный HA.

  PPM

THIS SECTION IS UNDER CONSTRUCTION


72.1.3.1. ПРЕОБРАБОТКА ИНФОРМАЦИИ ДЛЯ СЖАТИЯ

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

        +----------------+
        |     Data       |
        +----------------+
            |
            V
        +----------------+
        |   Preprocess   |
        +----------------+
            |
            V
        +----------------+
        |    Compress    |
        +----------------+
                |
                V
        +================+
        |   Compressed   |
        |      Data      |
        +================+
                |
                V
        +----------------+
        |  Decompress    |
        +----------------+
            |
            V
        +----------------+
        |  Postprocess   |
        +----------------+
            |
            V
        +----------------+
        |      Data      |
        +----------------+

Приведем пример:
Есть выполняемый файл для Windows x86 PE формата.
Естественно в секции кода есть много инструкций типа:

    CALL NEAR  SubName	; Вызов подпрограммы

с кодом:  E8 xx xx xx xx, где XXXXXXXX - относительное смещение подпрограммы
                     относительно начала следующей инструкции

Например:
      E8 FF FF 03 05	; Virt Address = 00012345
      ...
      E8 FF FE 72 34	; Virt Address = ...

Мы можем пройти всю секцию кода и заменить это относительное смещение на
абсолютное перед тем как делать компрессию.

      E8 00 01 22 33	; Val = VirtAddr + FFFF0305
      ...
      E8 00 01 22 33	; Val = VirtAddr + FFFE7234

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

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

      E8 FF FF 03 05	; Rel = 00012233 - VirtAddr = FFFF0305
      ...
      E8 FF FE 72 34	; Rel = 00012233 - VirtAddr = FFFE7234


72.1.4. СЖАТИЕ ДАННЫХ С ПОТЕРЯМИ

THIS SECTION IS UNDER CONSTRUCTION

       С Потерями
      /           \
      Спектральные    Фрактальные
      алгоритмы        алгоритмы

    Основа всего спектр
    ДКП ДПФ

    MP3 (MPEG1, Layer3)
    JPEG
    Фрактальные алгоритмы


72.1.4.1. СПЕКТР И ПРЕОБРАЗОВАНИЕ ФУРЬЕ

THIS SECTION IS UNDER CONSTRUCTION

  Спектр

Любой переодический сигнал можно представить в виде ряда Фурье
(разложение Фурье).

Пример сложения двух синусоид:
(это диаграмма - амплитуда (Y)/время (X))

Спектр сложения двух синусоид:
(это диаграмма - амплитуда (Y)/частота(X))

Можно сравнить что короче (длинный массив выборок амплитуда-время
или пара чисел частот).

Вот так выглядит спектр реального звука:

  Основы

Как узнать входит ли частота или нет?
Умножить на синусоиду с частотой и сложить.
Если входит то сигнал будет отличаться от нуля

Если не входит то будет близок к нулю

Как правило для обработки берут кусок от 32-1024 отчетов.

  Преобразование фурье

Преобразование Фурье:

Обратное преобразование Фурье:

Дискретное преобразование Фурье:

Обратное дискретное преобразование Фурье:

В пространстве Фурье image имеет два типа информации:
    Реальная часть:
        Амплитуда волны
        Информация о частотах волн
    Мнимая часть:
        Фаза волны
        Структура image

Пример первых функций для двухмерного ДПФ:

  Дискретное косинусное преобразование

Дискретное косинусное преобразование (ДКП):

Обратное ДКП:

Пример первых частот ДКП для 1D случая (звук):

Пример первых частот ДКП для 2D случая (картинка):

Пример результатов ДКП:


72.1.4.2. КОЛОРМЕТРИЯ

THIS SECTION IS UNDER CONSTRUCTION

Что такое цвет?

Чуствительность глаза

Человек в среднем различает ~ 3 * 10^5 цветов
    из них:
        256 оттенков интенсивности
        200 градаций цветового тона	(128 для красного)
        10  уровней насыщенности	(16 для желтого, 23 для красного)

Чуствительность глаза к RGB

Чувствительность глаза к CIE XYZ

Аддитивные и субтрактивные цвета:

Аддитивные цвета это когда они складываются.
например источники света - пиксели на экране.
Основные аддитивные цвета:
    Red	красный
    Green	зеленый
    Blue	синий

Субтрактивные цвета - цвета которые вычитаются
т.е. не отдают, а поглощают,
как например пичменты чернил на бумаге.
Основные субтрактивные цвета:
    Cyan	голубой
    Magenta	пурпурный
    Yellow	желтый

Вот какаим образом рождается цвет из субтрактивных цветов:

Смешивание цветов:

  Цветовые модели

  RGB/CMY

     R	G       B
Red	(1	0	0)
Blue	(0	0	1)
Green	(0	1	0)
Black	(0	0	0)
Yellow	(1	1	0)
Cyan	(0	1	1)
Magenta	(1	0	1)
White	(1	1	1)
Grey	(0.5	0.5	0.5)

Собственно говоря RGB куб является также и CMY кубом

|C|    |1|   |R|
|M|  = |1| - |G|
|Y|    |1|   |B|

    C	M	Y
Cyan	(1	0	0)
Magenta	(0	1	0)
Yellow	(0	0	1)
Black	(1	1	1)
White	(0	0	0)
Red	(0	1	1)
Green	(1	0	1)
Blue	(1	1	0)

На практике кроме CMY в целях экономии цветных расходных
материалов используют CMYB.
CMYB это CMY + Black (черный)

Поскольку равные количества CMY дает Black, то можно его
напечатать, а поверх разницу между цветами и black,
будет тоже самое.

CMYB
    K = min(C,M,Y)
    Ck = C - K
    Mk = M - K
    Yk = Y - K

RGB:

CMY:

CMYB:

  HLS

HLS (Hue-Lighness-Saturation)
    оттенок-светлота-насыщенность).

Н как у HSV
S как у HSV
Но L отличается, не простой конус, а двойной конус.

     H	L	S
Red	(0'	0.5	1)
Green	(120'	0.5	1)
Blue	(240'	0.5	1)
Black	(X	0	X)
White	(X	1	X)

Преобразование из RGB:

    L = [MAX(R,G,B) + MIN(R,G,B)] / 2
    if (MAX(R,G,B) == MIN(R,G,B)
    then
        S = 0
        H = undefined
    else
        if L < 0.5 then
            S = (Max-Min) / (Max+Min)
        else
            S = (Max-Min) / (2 - Min - Max)
        endif
    endif
    if R = Max then
        H = (G - B) / (Max - Min)
    else if G = Max then
        H = 2 + (B - G) / (Max - Min)
    else // B = Max
        H = 4 + (R - G) / (Max - Min)
    endif

    H = H * 60'
    if H < 0 then H = H + 360'

  HSV

Hue-Saturation-Value
цвет-насыщенность-яркость

Н - угол (цветовой тон) 0'-360'
S - насыщенность	0..1
V - яркость		0..1

Откуда растут ноги:

HSV - это цветовой конус

     H      S       V
Red	(0'	1	1)
Green	(120'   1	1)
Blue	(240'	1	1)

Преобразование из RGB:

    V = MAX(R,G,B)
    S = (V - MIN(R,G,B)) / V

    H = 60' * {1/(S*V) *
          (F(V-R)*(G-B) +  F(V-G)*(B-R) + F(V-B)(R-G))
      + (2 + 2F(V-B)) * F(V-R)}

    где
    F(X) = | 1   X == 0 |
           | 0   X != 0 |

  TLS

Tone-Saturation-Layer

T - цветовой тон (-1..1)
S - насыщенность (0..1)
L - уровень      (0..1)

Преобразование из RGB:

    L = (R + G + B) / 3

    S = SQRT{(R - L)^2 + (G - L)^2 + (B - L)^2} / L / SQRT(6)

    T = sign(G - B) * acos(2 * (R-L) - (G - L) - (B - L))
       / SQRT(6 * PI * SQRT{(R-L)^2 + (G-L)^2 + (B-L)^2})

  XYZ

X + Y + Z = 1

RGB на XYZ:

|X|    | 2.36460  -0.51515   0.00520|   |R|
|Y|  = |-0.89653   1.42640  -0.01441| * |G|
|Z|    |-0.46807   0.08875   1.00921|   |B|

  YIQ

YIQ - цветовая схема используемая в телевидении в США (в NTSC)

Y brightness (тоже самое как CIE Y)
I (orange-cyan color)   синфазный сигнал
Q (green-magenta color) интегрируемый сигнал

|Y|	|0.30	 0.59	0.11|	  |R|
|I|  =	|0.60	-0.28  -0.32|  *  |G|
|Q|	|0.21	-0.52	0.31|	  |B|

  YUV

YUV

    Y	- brihtness
    U,V	- vertical colors

Y = 0.3R + 0.59G + 0.11B

Y = 0 black
Y = 1 white

|Y|	|0.299	 0.58	0.14|	  |R|     | 0 |
|U|  =	|0.500	-0.41  -0.08|  *  |G|  +  |128|
|V|	|0.169	-0.33	0.50|	  |B|     |128|

|R|     |1     0       1.402|     /  |Y|   | 0 |  \
|G|  =  |1    -0.344  -0.714|  *  |  |U| - |128|  |
|B|     |1     1.772   0    |     \  |V|   |128|  /


72.1.4.3. JPEG

THIS SECTION IS UNDER CONSTRUCTION

    Перевод RGB в YUV
    Дискретизация
    DCT
    Квантование
    Зигзаг-сканирование
    RLE
    Haffman


72.1.4.4. MPEG

THIS SECTION IS UNDER CONSTRUCTION

Требования:
    Произвольный доступ
    Быстрый поиск вперед/назад
    Аудиовизуальная синхронизайия

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

    I - Independed  (сжаты независимо не от кого)
    P - Predicted   (сжаты основываясь на другом изображении)
    B - Bidirection (сжаты основываясь на двух изображениях)
    DC - сжаты независимо с большой потерей качества
         (используются при поиске)

MPEG-2 сжатие:
    Подготовка макроблоков 8x8
        для I - сжимается
        для P - сжимается независимо или разность между кадрами
    Перевод макроблока в YUV
    Для P- и B- вычисление разности с опорным макроблоком
    DCT
    Квантование
    Зигзаг-сканирование
    RLE
    Haffman


72.1.4.5. ВЕЙВЛЕТЫ

В ДПФ и ДКП мы разлагали сигнал в спектр синусоидальных волн.
Но бывают случаи когда более эффективно использовать не синусоиду
для разложения, а сигнал другой формы (вейвлет).
Остальные принципы все такие же как и были.

Пример некоторых часто используемые вейвлеты:

Пример первых частот вейвлете Хаара (2D случай).


72.1.4.6. ФРАКТАЛЬНОЕ СЖАТИЕ

THIS SECTION IS UNDER CONSTRUCTION

Изображение представляется в виде IFS (Iterated Function System) коэффициентов.
IFS - это набот трехмерных аффинных преобразований

  |X{n}|   |a  b|   |X{n-1}|   |e|
  |Y{n}| = |c  d| * |Y{n-1}| + |f|

Примеры некоторых фракталов

Оригинальное:

stage 1:

stage 2:

stage 3:

stage 8:


72.1.4.7. MP3 (MPEG1 LAYER 3)

THIS SECTION IS UNDER CONSTRUCTION


72.2. КРИПТОГРАФИЯ

THIS SECTION IS UNDER CONSTRUCTION

Зачем это надо?

Authentication

Integrity

  Атака на данные

  Стеганография

Стеганография - искуство прятать данные

        классика:	татуировка на бритой голове, потом рост волос

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

Рассеивание
Перемешивание


72.2.2. ШИФРОВАНИЕ С ЗАКРЫТЫМ КЛЮЧЕМ

        С закрытым ключем
           /        \
        Блоковые    Поточные

  Блоковые

E(M) = C
D(C) = M

  DES

THIS SECTION IS UNDER CONSTRUCTION

  Блоковые
    3DES
    IDEA
    BlowFish
    CAST-128
    RC2

  Потоковые

  RC4

 Потоковые
    RC4

THIS SECTION IS UNDER CONSTRUCTION


72.2.3. ШИФРОВАНИЕ С ОТКРЫТЫМ КЛЮЧЕМ

С открытым ключем
    Теоретико-числовые (RSA, ElGamal, Pohlig-Hellman)
    Кодовые (McEllice,Niederreiter,Krouk)
    На эллиптических функциях

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

Шифрование:

Расшировка:

В реальности как правило на открытом ключе шифруют сеансовый ключ, а сам сеанс
идет на закрытом сеансовом ключе.

C открытым ключем:
    RSA

    C = M^e mod n
    M = C^d mod n = (M^e)^d mod n = M^(ed) mod n

    KU = {e,n}		Открытый ключ  (Unrestricted key)
    KR = {d,n}		Закрытый ключ  (Restricted key)

    p,q - два больших простых числа

    n = p * q

    e, gcd(F(n),e) = 1, 1 < e < F(n)
        F(n) - функция Эйлера (число положительнызх челых чисел
            меньших n, и взаимно простых с n.
        Для n = p*q,  F(n) = (p-1)(q-1)
    d = e^(-1) mod F(n)

ECC (Elliptic Curve Cryptography)

Пример эллиптической группы E(GF(5)), E: Y^2 = X^3 + X + 1
Точки:
    P	(0,1)
    2P      (4,2)
    3P	(2,1)
    4P	(3,4)
    5P	(3,1)
    6P	(2,4)
    7P	(4,3)
    8P	(0,4)
    9P	O
    10P  =  P

Пример эллиптической группы E(GF(23)), E: Y^2 = X^3 + X + 1

    O	(0,1)	(0,22)	(1,7)	(1,16)
    (3,10)	(3,13)	(4,0)	(5,4)	(5,19)
    (6,4)	(6,19)	(7,11)	(7,12)	(9,7)
    (9,16)	(11,3)	(11,20)	(12,4)	(12,19)
    (13,7)	(13,16)	(17,3)	(17,20)	(18,3)
    (18,20)	(19,5)	(19,18)


72.2.4. АУТЕНТИФИКАЦИЯ

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

Большенство моделей основаны на challenge-respnose
Пароль знают обе стороны.

    Алиса			Боб
          ------------>			Запрос (я Алиса)
        <------------	Rb		Случайное число
        ------------>   K(Rb)		Подписаное паролем или его hash
                        Боб знает что это Алиса
        ------------>	Ra
        <-----------    K(Ra)
                        Алиса знает что это Боб


72.2.4.1. ОБМЕН КЛЮЧАМИ

THIS SECTION IS UNDER CONSTRUCTION

Обмен ключами:
    Diffie-Hellman

    q - большое прсотое число
    a - его первообразный корень

   Alice
    выбирает число Xa < q
    вычисляет Ya = a^(Xa) mod q
   Bob
    выбирает число Xb < q
    Вычисляет Yb = a^(Xb) mod q
   Обмениваются Ya,Yb
   Alice
    ключ K = (Yb)^(Xa) mod q
   Bob
    ключ K = (Ya)^(Xb) mod q

Взлом сводится к решению задачи дискретного логарифмирования

Oakley


72.2.4.2. АЛГОРИТМ НИДХЕМА-ШРЕДЕРА

1.	Алиса -> Трент
        (Алиса, Боб, СЧА=случайное число)

2.	Трент генерирует случайный сеансовый ключ Kab
    C = C{b}(Kab, Алиса)
    Трент -> Алиса
        C{а}(СЧА, Боб, Кab, C)

3.	Алиса распаковыват своим ключем
    Проверяет СЧА, берет Kab
    Алиса -> Боб
        С = С{b}(Kab, Алиса)

4.	Боб распаковывает Kab, генерирует CЧБ
    Боб -> Алиса
        C{ab}(CЧБ)

5.	Алиса распаковывает и посылает
    Алиса -> Боб
        C{ab}(СЧБ-1)

6.	Боб распаковывает и убеждается что это Алиса


72.2.4.3. KERBEROS

1.	Алиса -> Трент
        (Алиса, Боб)

2.	Трент генерирует время B, срок действия DT
    Трент -> Алиса
        C{a}(B, DT, Kab, Боб)
        С{b}(B, DT, Kab, Алиса)

3.	Алиса -> Боб
        C{ab}(Алиса, B)
        C{b} (B, DT, Kab, Алиса)

4.	Боб -> Алиса
        С{ab}(B+1)


72.2.5. ХЭШИ И ЦИФРОВАЯ ПОДПИСЬ

THIS SECTION IS UNDER CONSTRUCTION

Хэши:
    MD5
    MD4
    SHA-1
    HMAC
    RIPEMD-160

MD5:

SHA-1:

Цифровая подпись
    DSS/DSA

    С = E(F(M,A)K)
        M - message
        A - address
        K - private key

Проверка цифровой подписи
    по public key

RSA digital signature


72.2.5.1. ЦИФРОВОЙ КОНВЕРТ

THIS SECTION IS UNDER CONSTRUCTION


72.2.5.2. ЦИФРОВЫЕ СЕРТИФИКАТЫ

THIS SECTION IS UNDER CONSTRUCTION


72.2.6. ДОВЕРЕННОЕ БРОСАНИЕ МОНЕТЫ

THIS SECTION IS UNDER CONSTRUCTION

Доверенное бросание монеты

Базируется на том, что
    X^2 = A    имеет 2 корня на простом поле

    Alice
        выбирает простые большие p,q
        посылает бобу n = p * q
    Bob
        выбирает случайное число u в интервале [1, n/2]
        посылает Алисе z = u^2
    Alice
        используя p и q вычисляет четыре квадратных корня
            z mod n  (+-x, +-y)
        Выбирает корни между [1,n/2] их будет 2
            u - это один из них, но какой неизвестно
        Выбирает корень посылает Бобу следующую info
            Определяет наименьший i, такой что в корнях x,y
            для которого значение разряда i различается
        Посылает Бобу пару {i, значение бита[i] в корне выбранном алисой}
        (Алиса на может посылать весь корень).
    Bob
        Сообщает угадала ли Алиса и присылает u
    Alice
        Присылает Бобу p и q на проверку


72.2.7. КВАНТОВАЯ КРИПТОГРАФИЯ

THIS SECTION IS UNDER CONSTRUCTION


72.2.8. АЛГОРИТМ ШОРА

Алгоритм Шора (P.W.Shor) 1994 год
Алгоритм факторизации (разложения на множители)

Пусть нам надо факторизовать число n = p*q

Находим (осредством квантовых вычислений) период С Функции F(X) = a^X mod n,
такой что бы a^c = 1 mod n
Пусть 2^c = 1 mod n

Тогда
    p = НОД(2^(C/2) + 1, n)
    q = НОД(2^(C/2) - 1, n)

НОД можно рассчитать по алгориму Евклидв


72.2.9. АЛГОРИТМ ЕВКЛИДА

Алгоритм Евклида основан на том что отображение:

    (a, b) ->  (a mod b, b)

сохраняет HОД.

Пример:
    (21, 15)
    21 mod 15 = 6
    15 mod 6  = 3
    6  mod 3  = 0,  соответсвенно НОД(21,15) = 3

    (21, 8)
    21 mod 8  = 5
    8  mod 5  = 3
    5  mod 3  = 2
    3  mod 2  = 1,  соответсвенно НОД(21,8) = 1

Двоичный алгоритм Евклида.
основан на отображении:

    (a, b) -> ((a-b)/2, b),  если а и b - нечетные
           -> (a/2, b)	 если a - четное, b - нечетное
           -> (a,   b/2)     если а - нечетное, b - четное


72.50. НЕКОТОРЫЕ СВЕДЕНИЯ ИЗ ТЕОРИИ ВЕРОЯТНОСТИ

THIS SECTION IS UNDER CONSTRUCTION

p(X)	- вероятность события Х

p(X,Y)  - вероятнось и события Х и события Н

p(X/Y)  - условная веросяность
          вероятность события X, при условии что произошло событие Y

    0 <= P(X) <= 1

    P(A) = m/n

      _
    P(A) = 1 - P(A)

    P(A+B) = P(A) + P(B)        	если несовместные
    P(A+B) = P(A) + P(B) - P(AB)	если совместные

               P(AB)
    P(A/B) = ---------
            P(B)

    P(AB) = P(A) * P(B/A)
    P(AB) = P(B) * P(A/B)

          P(A) * P(B/A)
    P(A/B) = ---------------	Теорема Байеса
                   P(B)

               _
    P(A\B) + P(A\B) = 1

    P(AB) = P(A) * P(B)		если события независимые

    Монета (Coin)
        Орел (Heads)
        Решка (Tail)

    Какова вероятность что выпадут 3 орла подряд?

    P(H.H.H) = 1/2 * 1/2 * 1/2 = 1/8

    Кость (Die)
    Какова вероятность что выбросим 12 очков?
        6+6

        P(12) = 1/6 * 1/6 = 1/36

    Какова вероятность что выбросим 11 очков?
        P(11) = P(6+5) + P(5+6) = 2/36

    Какова вероятность что выбросим 10 очков?
        случаи:
        6+4	5+5	4+6
        P(10) = 3 * 1/36 = 3/36

    Какова вероятность что выбросим 9 очков?
        6+3	5+4
        4+5	3+6

    а 8 очков:
        6+2	5+3	4+4
        2+6	3+5

    7 очков:
        6+1	5+2	4+3	3+4	2+5 	1+6

Теперь проиллюстрируем на примере колоды карт:

    В колоде 52 карты
    4 масти (Hearts = Червы, Diamons = Буби, Spides = Пики, Clubs = Трефы)
    в каждой масти 13 карт:
        A K Q J 10 9 8 7 6 5 4 3 2
    (A = Ace = Туз)
    (K = King = Король)
    (Q = Queen = Дама)
    (J = Jack = Валет)

Вероятность вытащить из колоды Туза бубей

    P(AD) = 1 / 52   (0.019)

Вероятность вытащить из колоды туза (неважно какой масти)

    P(A) = P(AH) + P(AD) + P(AS) + P(AC) =
           1/52  + 1/52  + 1/52  + 1/52  =  4/52    (0.077)

    другой спрсоб - нам подходят 4ре равновероятные карты.

Вероятность вытащить из колоды карту масти буби:

    P(D) = 13 / 52  (0.25)
    (помним что в масти 13 карт)

Вероятность вытащить 2 красных туза
    P(AR.AR) = 2/52 * 1/51    = 2/2652  (0.00075)

    есть только 2 варианта:
    XY	AD потом AH	1/52 * 1/51
    YX      AH потом AD     1/52 * 1/51

Вероятность вытащить 2 туза
    P(A.A) = 4/52 * 3/51     = 12/2652  (0.0045)

варианты:

    варианты:
        AH.AD	AH.AS	AH.AC
        AD.AH	AD.AS	AD.AC
        AS.AH   AS.AD   AS.AC
        AC.AH   AC.AD   AC.AS
    таким образом всего 12 вариантов

Вероятность вытащить точно одного туза из двух карт:

    P(A.X) = 2 * 4/52 * 48/51   = 384/2652 (0.144)

    Вариантов 2:	AX  или XA

    P(A.X) =  4/52 * 48/51
    P(X.A) = 48/52 *  4/51

Вероятность вытащить хотя бы одного туза из двух карт

    Вариантов 2:	A* и XA

    P = P(A*) + P(XA)

    P(A*) = 4/52
    P(XA) = 48/52 * 4/51

    P = 4/52 + 48/52 * 4/51  = (51 * 4 + 48 * 4) / 2652 =
      = 396 / 2652 (0.149)

Вероятность вытащить две карты масти Diamods

    P(D.D) = 13/52 * 12/51 = 156 /2652    (0.058)

    первую карту - 13 из 52
    вторую карту - 12 из 51

Вероятность вытащить две карты одной масти

    Ecть 4 варианта:
        DD HH SS CC

    P = 4 * P(D.D) = 4* 13/52 * 12/52 = 624/2652 (0.235)

    И действительно возможные варианты:
           >DD<  DH	  DS   DC
        HD  >HH<  HS   HC
        SD   SH  >SS<  SC
        CD   CH   CS  >CC<

    Вероятность должна быть немного меньше чем 1/4.

Вероятность вытащить точно два туза из трех карт.

    Ситуаций много:
        AAX	AXA	XAA

    вероятность для одного случая:
    AAX	4/52  * 3/51  * 48/50
    AXA	4/52  * 48/51 * 3/50
    XAA	48/52 * 4/51  * 3/50

    P = 3 * 4/52 * 3/51 * 48/50 = 1728 / 132600 = (0.013)

Вероятность вытащить точно два туза из четырех карт:

    Ситуаций еще больше (комбинаторика рулит)

    AAXX	AXAX	AXXA
    XAAX	XAXA	XXAA

    Вероятность:
    P = 6 * 4/52 * 3/51 * 48/50 * 47/49

Роль информации в событии

Кто-то говорит что у него двое детей и один из них мальчик
Какова вероятность что у него два мальчика?

    Рассмотрим все возможные случаи с парами детей:
        MM
        MF
        FM
        FF (не вписывается в нашу задачу)
    Эти случаи равновероятны:
    Поэтому вероятность что у него 2 мальчика = 1/3

Кто-то говорит что у него двое детей и старший из них мальчик
Какова вероятность что у него два мальчика?

    Рассмотрим все возможные случаи с парами детей:
        MM
        MF
        FM	(не подходит)
        FF	(не подходит)
    Поскольку случаи равновероятные
    То вероятность что у него 2 мальчика = 1/2

Парадокс дней рождений

2 человека - какова вероятность что день рождения совпадет?

        A-B

    1/365

    не совпадет

    364/365

3 человека - какова вероятность что день рождения совпадет?

    A
      /  \
     B  - C

     вероятность совпадения для каждой из пар = 1/365
     таких пар = 3

     Таким образом получаем  ~3/365

     более точные подсчеты:

      не совпадет

      364   363
      --- * ---
      365   365

    365*365 - 364*363

    X^2 - (X-1)(X-2) = X^2 - X^2 + 3*X - 2 = 3*365-2

4 человека

    A - B
    | X |
    D - C

     всего 6 пар.  Вероятность совпадения в паре = 1/365

     6/365

THIS SECTION IS UNDER CONSTRUCTION

Понятно что у 366 человек - вероятность  = 1

Корреляция:

Удобно смотреть на графике:
            _          _
    Y - Y  от  X - X


73. КОМПЬЮТЕРНАЯ ГРАФИКА

    o 2D компьютерная графика
    o Клеточные автоматы
    o Аффинные преобразования
    o 3D компьютерная графика
    о Моделирование

THIS SECTION IS UNDER CONSTRUCTION


73.1. ДВУМЕРНАЯ КОМПЬЮТЕРНАЯ ГРАФИКА

THIS SECTION IS UNDER CONSTRUCTION

Примитивы 2D графики

    Line
    Polyline
    Rectangle (прямоугольник)
        Каркас
        Закрашенный
    Circle/Ellipse
        просто
        Сектор
            Граничный
            Закрашенные
    Закраска контура

  Рисование прямых линий

Отрезки прямые
    Y = A * X + B
    алгоритм Люка
    алгоритм Брезенхейма

DDA

  Рисование окружностей и дуг

Окружности и дуги
    X^2 + Y^2 = R^2
    алгоритм Брезенхейма

  Рисование Эллипсов

Эллипсы
    X^2/A^2 + Y^2/B^2 = 1
    алгоритм Руа

Параболы
    алгоритм Руа

Гиперболы
    обобщенный метод Брезенхейма

  Aliasing

  Заполнение контура

Заполнение контура (раскрашивание)
    алгоритм Люка
    алгоритм Смита
    алгоритм Павлидиса


73.2. КЛЕТОЧНЫЕ АВТОМАТЫ

(Дискретные преобразования)

THIS SECTION IS UNDER CONSTRUCTION

  Гамма

Гамма - описывает как воспроизводиться яркостная компонента изображения
    т.е. светимость.
    X = Y^Gamma
    Например у RGB - целых 3 гаммы: по одному для каждого компонента цвета
    Гамма - характеристика нелинейности

    Гамма = 1 для идеального дисплея имеющего совершенно линейную характеристику
          от белого к черному.

    Для IBM PC: серый:
        30% Красный
        59% Зеленый
        11% Синий

  Гамма-коррекция

Гамма-корекция
    поскольку видим логарифмически

    S = c * r^gamma

    S - Яркость на выходе
    с - константа (обычно = 1.0)
    r - яркость на входе
    gamma - гамма

    Яркость = Входной_сигнал ^ Гамма
    Яркость = (Входной_сигнал + Чернота_экрана) ^ Гамма
    Обычное значение гамма = 2.3-2.6
    (но видеокарты могут сами делать частичную коррекцию типа 1.45)
    Для Mac = 1.8, для PC = 2.2, для SGI = 2.5

  Пороговое отсекание

Пороговое отсекание
    Если интенсивность больше > N оставляем
    иначе 0.

  Матрицирование

Матрицирование
    Матрица Риландера

    |  0   8  2  10  |
    |  4  12  6  14  |
    |  3  11  1   9  |
    |  7  15  5  13  |

       0     1      2      3      4      5      6      7

    +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+
    |    | |X   | |X X | |X X | |X X | |X X | |X X | |X X |
    |    | |    | |    | |    | |X   | |X   | |X X | |X X |
    |    | |  X | |  X | |X X | |X X | |X X | |X X | |X X |
    |    | |    | |    | |    | |    | |  X | |  X | |X X |
    +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+

      8      9      10     11     12     13     14     15
    +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+
    |XXX | |XXX | |XXXX| |XXXX| |XXXX| |XXXX| |XXXX| |XXXX|
    |X X | |X X | |X X | |X X | |XXX | |XXX | |XXXX| |XXXX|
    |X X | |X XX| |X XX| |XXXX| |XXXX| |XXXX| |XXXX| |XXXX|
    |X X | |X X | |X X | |X X | |X X | |X XX| |X XX| |XXXX|
    +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+

  Псевдотонирование

Псевдотонирование
        Матрица Байтера

    |   0   8   2  10 |
    |  12   4  14   6 |
    |   3  11   1   9 |
    |  15   7  13   5 |

    Моделирование уровней яркости

Точечные процессы
    Просветление
        V = V + b	для каждого канала
                понятно что арифметика с насыщением
                и b - может быть отрицательным
    Негатив
        V = MAX_V - V

    Пороговые изображения
    Увеличение контраста
    Псевдораскрашивание
        Все что попадает в уровень интенсивности от A..B
        краситься определенным цветом.

Клеточные автоматы

Пространственные процессы
    Свертка
        НЧ фильтр
            |1/9  1/9  1/9|
            |1/9  1/9  1/9|
            |1/9  1/9  1/9|

            |0.1  0.1  0.1|
            |0.1  0.2  0.1|
            |0.1  0.1  0.1|

            |1/16  1/8  1/16|
            |1/8   1/4  1/8 |
            |1/16  1/8  1/16|
        ВЧ фильтр
            |-1   -1   -1|
            |-1   9    -1|
            |-1   -1   -1|

            |0    -1    0|
            |-1   5    -1|
            |0    -1    0|

            |1    -2    1|
            |-2   5    -2|
            |1    -2    1|
        усиление края
            методом сдвига и разности
                |0   0    0|
                |-1  1    0|  Вертикальные края
                |0   0    0|

                |0   -1   0|
                |0   1    0|  Горизонтальные края
                |0   0    0|

                |-1   0   0|   Вертикальные и горизонтальные
                |0    1   0|
                |0    0   0|
            методом выравнивающего фильтра
                |-1   0   1|
                |-1   0   1|
                |-1   0   1|
                |-1   0   1|
                |-1   0   1|

                |-1  -1  -1  -1  -1|
                | 0   0   0   0   0|
                |-1  -1  -1  -1  -1|

            методом направленного градиента
                | 1   1   1|
                | 1  -2   1|  N   (North)
                |-1  -1  -1|

                | 1   1   1|
                |-1  -2   1|  NE
                |-1  -1   1|

                |-1   1   1|
                |-1  -2   1|  E   (East)
                |-1   1   1|

                |-1  -1   1|
                |-1  -2   1|  SE
                | 1   1   1|

                |-1  -1  -1|
                | 1  -2   1|  S	  (South)
                | 1   1   1|

                |-1  -1  -1|
                | 1  -2  -1|  SW
                | 1   1   1|

                | 1   1  -1|
                | 1  -2  -1|  W	   (West)
                | 1   1  -1|

                | 1   1   1|
                | 1  -2   1|  NW
                |-1  -1  -1|
            по Лапласу
                    | 0   1   0|
                | 1  -4   1|  LAP1
                | 0   1   0|

                |-1  -1  -1|
                |-1  8   -1|  LAP2
                |-1  -1  -1|

                |-1  -1  -1|
                |-1  9   -1|  LAP3
                |-1  -1  -1|

                | 1  -2   1|
                |-2   4  -2|  LAP4
                | 1  -2   1|

        размытие
            |1  1  1  1  1|
            |1  1  1  1  1|
            |1  1  1  1  1|
            |1  1  1  1  1|
            |1  1  1  1  1|

    Определение точек
            |-1 -1  -1|
            |-1  8  -1|
            |-1 -1  -1|

    Определение линий
            |-1 -1 -1|
            | 2  2  2|  горизонтальная
            |-1 -1 -1|

            |-1 -1  2|
                |-1  2 -1|   +45'
            | 2 -1 -1|

            |-1  2 -1|
            |-1  2 -1|  вертикальная
            |-1  2 -1|

            | 2 -1 -1|
            |-1  2 -1|   -45'
            |-1 -1  2|

    Определение краев по Собелю
                    |-1  0   1|
        X core	|-2  0  -2|
            |-1  0   1|

            | 1  2  1|
        Y core  | 0  0  0|
            |-1 -2 -1|

    Вычисление градиента
                |-1 0|   |0 -1|
                | 0 1|   |1  0| по Рос???

            |-1 -1 -1|  |-1 0 1|  по Превитту
            | 0  0  0|  |-1 0 1|
            | 1  1  1|  |-1 0 1|

            | 0  1  1|  |-1 -1  0|
            |-1  0  1|  |-1  0  1| по Превитту
            |-1 -1  0|  | 0  1  1| (диагональный)

            |-1 -2 -1|  |-1 0 1|
            | 0  0  0|  |-2 0 2|  по Собелю
            | 1  2  1|  |-1 0 1|

            | 0  1  2|  |-2 -1  0|
            |-1  0  1|  |-1  0  1| по Собелю
            |-2 -1  0|  | 0  1  2| (диагональный)

            |+5 -3 -3|  |+5 +5 -3|
            |+5  0 -3|  |+5  0 -3|  по Кирчу
            |+5 -3 -3|  |-3 -3 -3|

    Заострение
            | 0  -1   0|
            |-1   9  -1|
            | 0  -1   0| /5

    Рельеф
            |1  0  0|	135'
            |0  0  0|
            |0  0 -1|	/1 + 128

    Усредненное фильтрование
            Выбираем наиболее среднее значение пикселя из 3x3
            Не вычисляем а дискретно выбираем
            (позволяет удалить случайный шум, т.к. он сто пудово
                 будет не в середине).

    Комбинирование изображений

    Маштабирование
        Интерполяция цвета


73.3. АФФИННЫЕ ПРЕОБРАЗОВАНИЯ

Преобразования:

----------------------------------------------------------------------------
Transformation		Eucledian	Simularity	Affine	Projective
----------------------------------------------------------------------------
Rotation		Yes		Yes		Yes	Yes
Translation             Yes		Yes		Yes	Yes
Uniform scaling		No		Yes		Yes	Yes
Non-uniform scaling     No		No		Yes	Yes
Shear			No		No		Yes	Yes
Perspective projection	No		No		No	Yes
Composition of project.	No		No		No	Yes
----------------------------------------------------------------------------
Invariants
----------------------------------------------------------------------------
Length			Yes		No		No	No
Angle                   Yes		Yes		No	No
Ratio of length		Yes		Yes		No	No
Parallelism		Yes		Yes		Yes	No
Incidence		Yes		Yes		Yes	Yes
Cross ration		Yes		Yes		Yes	Yes
----------------------------------------------------------------------------

    u{1} = a{1,1} v{1} + a{1,2} v{2} + a{1,3} v{3}
    u{2} = a{2,1} v{1} + a{2,2} v{2} + a{2,3} v{3}
    u{3} = a{3,1} v{1} + a{3,2} v{2} + a{3,3} v{3}

    |u1|   |a11 a12 a13||v1|
    |u2| = |a21 a22 a23||v2|
    |u3|   |a31 a32 a33||v3|

2D

Маштабирование (dilatation)

    |a   0   0|
    |0   b   0|
    |0   0   1|

Вращение (rotation) CCW

    | c  s   0|
    |-s  c   0|
    | 0  0   1|

Сдвиг (translation)

    |1   0   0|
    |0   1   0|
    |a   b   1|

Зеркальное отражение

    |1   0   0|
    |0  -1   0|	about X-axe
    |0   0   1|

    |-1  0  0|
    | 0  1  0|	about Y-axe
    | 0  0  1|

    |-1  0  0|
    | 0 -1  0|	через центр координат
    | 0  0  1|

    |0  1  0|
    |1  0  0|	через линию x=y  (Swap axes)
    |0  0  1|

Shear

    Y shear
    |1   0   0|
    |a   1   0|
    |0   0   1|

    X shear
    |1   b   0|
    |0   1   0|
    |0   0   1|

  3D

Сдвиг
    x' = x + a
    y' = y + b
    z' = z + c

    |1  0  0  0|
    |0  1  0  0|
    |0  0  1  0|
    |a  b  c  1|

Маштабирование

    |a  0  0  0|
    |0  b  0  0|
    |0  0  c  0|
    |0  0  0  1|

Вращение CCW вокруг осей:

Вращение в пространстве не коммутативно
(порядок операций важен).
    c = cos a
    s = sin a

        | c   s   0   0 |
z 	|-s   c   0   0 |
    | 0   0   1   0 |
    | 0   0   0   1 |

    | 1   0   0   0 |
x	| 0   c   s   0 |
        | 0  -s   c   0 |
    | 0   0   0   1 |

    | c   0  -s   0 |
y	| 0   1   0   0 |
    | s   0   c   0 |
    | 0   0   0   1 |

Отражения

от	| 1   0   0   0 |
пл. xy	| 0   1   0   0 |
    | 0   0  -1   0 |
    | 0   0   0   1 |

    |-1   0   0   0 |
от пл.yz| 0   1   0   0 |
        | 0   0   1   0 |
    | 0   0   0   1 |

    | 1   0   0   0 |
от пл zx| 0  -1   0   0 |
    | 0   0   1   0 |
    | 0   0   0   1 |


73.4. МОДЕЛИРОВАНИЕ

THIS SECTION IS UNDER CONSTRUCTION

Отсечения
Разрезания

    u{1} = a{1,1} v{1} + a{1,2} v{2} + a{1,3} v{3} + a{1,4}
    u{2} = a{2,1} v{1} + a{2,2} v{2} + a{2,3} v{3} + a{2,4}
    u{3} = a{3,1} v{1} + a{3,2} v{2} + a{3,3} v{3} + a{3,4}

    |u1|   |a11 a12 a13 a14||v1|
    |u2| = |a21 a22 a23 a24||v2|
    |u3|   |a31 a32 a33 a34||v3|
    |1 |   |  0   0   0   1|| 1|

    12-степеней свободы.

Проекции

    Паралельные проекции

        Аксонометрическая проекция
        (проектирующие прямые перпендикулярны картинной плоскости)
            Триметрическая (все три угла с осями различны)
            Диметрическая
            Изометрическая (все три угла нормали с осями равны)

        Ортографическкая
        (картинная плоскость совпадает с координатной или паралельна ей)
        (фокус в бесконечности)
                R = right, L=left, T=top, B=bottom, F=far, N=near
            P(L,R,T,B,F,N)
            |2/(L-R)	0	0	-(R+L)/(R-L) |
            |      0  2/(T-B)	0	-(T+B)/(T-B) |
            |      0	0  2/(F-N)	-(F+N)/(F-N) |
            |      0	0	0		  1  |

        Косоугольная
            Свободная
            Кабинетная

Удаление невидимых линий
    Метод Z-буффера

Сплайны

Перспектива
    Видовое преобразование

        |1   0    0   0|
        |0   1    0   0|
        |0   0    1   0|
        |0   0   1/d  1|

    Перспективные проекции
        Однототечная
        Двухточечная
        Трехточечная

        V=fov, A=aspect, N=near, F=far
        P(V,A,N,F)
            |tan(V/2)/A	0		0		0    |
            |	0    1/tan(V/2)		0		0    |
            |	0	0	    (N+F)/(N-F)	   2NF/(N-F) |
            |	0	0		-1		0    |

    Сдвиг камеры назад
        |1   0   0   0|
        |0   1   0   0|
        |0   0   1  -d|
        |0   0   0   1|

Закраска
    метод Гуро
    метод Фонга

Трассировка лучей
        зеркальное отражение
    диффузное отражение
    идеальное преломление
    диффузное преломление

Текстурирование
    Проективные
    Сплошные
    Antialisaing
        Распределенная трассировка лучей

Метод излучательности


73.5. ОСНОВЫ ЛИНЕЙНОЙ АЛГЕБРЫ ИТД

THIS SECTION IS UNDER CONSTRUCTION

  Векторы

    |x1|    |x2|    |x1 + x2|
    |y1|  + |y2|  = |y1 + y2|
    |z1|    |z2|    |z1 + z2|

    |x1|    |x2|    |x1 - x2|
    |y1|  - |y2|  = |y1 - y2|
    |z1|    |z2|    |z1 - z2|

  скалярное произведение

    |x1|	|x2|
    |y1|  *	|y2|  =  x1*x2 + y1*y2 + z1*z2
    |z1|    |z2|

  векторное произведение

    |x1|	|x2|    | y1*z2 - z1*y2  |  CORRECT IT
    |y1| X 	|y2|  = | z1*x2 - z1*z2  |
    |z1|    |z2|    | x1*y2 - y1*z2  |

  Матрицы

  Сложение/Вычитание/Умножение на константу

    A + B = [a{ij} + b{ij}]

    cA  = c [a{ij}] = [ca{ij}]

    A - B = A + (-B)

    A + O = A = O + A

    A - A = O = -A + A

  Умножение матриц

    С = A * B

    с{ij} = a{i1}b{1j} + a{i2}b{2j} + ... + a{in}b{nj}

      A   *   B    =   AB
    m x n   n x r     m x r
    ^   ^   ^   ^
        |   |   |   |
    |   +---+   |
        |   same    |
    +-----------+
      size of AB

    A = | 1  1 |	A^2 = A*A = | 2 2 |
        | 1  1 |                | 2 2 |

    A^3 = A^2 * A =  | 4 4 |
             | 4 4 |

    A = |  2  4 |
        | -1 -2 |

    A^2 = 0

Вот они делители нуля.

Результат зависит от порядка матриц, в общем виде  AB != BA

    (A + B)^2 = A^2 + AB + BA + B^2

  Транспонированная матрица

    A^T транcпонированная матрица (столбцы поменяны со строками)

Если A^T = A, то A - симмитричная матрица

    (A^T)^T = A

    (kA)^T  = k(A^T)

    (A^n)^T = (A^T)^n,  для целых n >= 1

    (A + B)^T = A^T + B^T

    (AB)^T  = B^T * A^T

    (A + A^T)^T = A + A^T

  Обратная матрица

    A * A^-1 = I

    A^-1 * A  = I

Существует на для всех, надо чтобы det A != 0

    A = | a b |
        | c d |

               1     |  d   -b |
    A^-1 =  -------- | -c   a  |
             det  A

    det A = ad-bc

    det A = {11}|{22}{23}| - {12}|{21}{23}| + {13}|{21}{22}|
            |{32}{33}|       |{31}{33}|       |{31}{32}|

    (A^-1)^-1 = A

    (cA)^-1 =  1/c A^-1

    (AB)^-1 =  B^-1 * A^-1

    (A^T)^-1 = (A^-1)^T

    (A^n)^-1 = (A^-1)^n

    det(AB) = det A * det B

    det(A^-1) = 1 / det A

Применение матрицы к вектору


73.6. ИГРА ЖИЗНЬ

THIS SECTION IS UNDER CONSTRUCTION

    +--+--+--+
    |  |  |  |
    +--+--+--+
    |  |O |  |
    +--+--+--+
    |  |  |  |
    +--+--+--+

Правила:
    Если у клетки 1 или меньше соседей то она умерает от одиночества
    Если у клетки 4 или больше соседей то она умирает от перенаселения
    Если у клетки 3 соседа - то в ней рождается новая клетка


75. ПОДХОДЫ К AI

THIS SECTION IS UNDER CONSTRUCTION

    o Распознование образов
    о Функциональные и логические языки
    о Генетические алгоритмы


75.1. ОБУЧЕНИЕ

THIS SECTION IS UNDER CONSTRUCTION

Обучение это самообучающая система распознования образов.

Данные     +-----------------+ Пространство   +------------+
------- >  | Предварительная |------------- > | Построение |
       |  обработка      | состояний      |  границ    |
       +-----------------+		      +------------+


75.2. НЕЧЕТКАЯ ЛОГИКА

THIS SECTION IS UNDER CONSTRUCTION

  Нечеткие множества

  Операции в нечеткой логике

Операции в нечеткой логике:

NOT  - 1 минус элемент
NOT  - 1 минус каждый элемент
OR   - MAX каждого элемента
AND  - MIN каждого элемента

сложение
вычитание
умножение
деление

  Дефузификация

  Как это работает


75.3. НЕЙРОННЫЕ СЕТИ

THIS SECTION IS UNDER CONSTRUCTION

Обычно используют биполярное кодирование {-1,1}

Функции:

Нейронные сети:

Нейронная сеть 3-4-2

Логические элементы на нейронах:
OR:

XOR проблема неразрешима в нейронной сети 1го ранга.

XOR:

Сложные варианты:

Пример разбиения пространства состояний:


75.4. ПРОСТРАНСТВО СОСТОЯНИЙ

THIS SECTION IS UNDER CONSTRUCTION

Шары
Поверхности


75.5. ГЕНЕТИЧЕСКИЕ АЛГОРИТМЫ

THIS SECTION IS UNDER CONSTRUCTION

Задачи:

Сводятся к поиску экстремумов в пространстве состояний.

А случаи могут быть гораздо более сложные.

Основые принципы
    Кодирование
        прямое бинарное
        Грея
        F.P
        специальные алфавиты
    Оценка
    Скрещивание

Кодирование:

Размер популяции
    < 10 мало
    20-500 нормально
    1000 много

Отбор
    Турнир
        между N случайно выбранными членами популяции
    Элитаризм
        выбираем N лучших особей
    Рулетка
        вероятность отбора особи пропорцианальна ее полезности

Агрессивные варианты отбора
    отбор с усечением
    турнирный отбор с размером турнира 4 или больше
    уничтожение дубликатов

Задача представляется в виде вектора (хромосома)
Делается начальная популяция
для каждого поколения
    Тест приспособленности (оценка)
    Селекция (отбор особей к скрещиванию)
        например с оценкой выше средней выживают
        ниже средней нет
    Приминение к этим особям операций
        Кроссовер
            Одноточечный кроссовер
            Многоточечный кроссовер
            Uniform кроссовер (каждый бит случайно)
        Мутация
    Если решение найдено то конец.
затем повторяется для следующего поколения

  Скрещивание

Одноточечный кроссовер:

Многоточечный кроссовер:

Uniform кроссовер:
(для каждого бита)

Арифметический кроссовер:

Пример кроссовера для графов:

  Мутации

Простая одноточечная мутация

Мутация вставка

Мутация инверсия

Мутация перемешевание

Мутация обмен

  Эволюция


75.6. DATA MINING

THIS SECTION IS UNDER CONSTRUCTION

  Data Mining

Data Mining - исследование и обнаружение "машиной" в сырых данных скрытых знаний
которые:
    - ранее были неизвестны
    - нетривиальны
    - практически полезны
    - доступны для интерпретации человеком

  Задачи Data Mining

Задача классификации
    определение класса объекта по его характеристикам

Задача регрессии
    опеределение по известным характеристикам объекта значения
    некоторого его параметра

Поиск ассоциативных правил
    нахождение зависимостей между объектами и событиями

Задача кластеризации
    Поиск независимых групп (кластеров) и их характеристик
    в множестве анализируемых данных.

  OLAP

THIS SECTION IS UNDER CONSTRUCTION


80. ПРОГРАМНОЕ ОБЕСПЕЧЕНИЕ

THIS SECTION IS UNDER CONSTRUCTION


80.1.1. BIOS

THIS SECTION IS UNDER CONSTRUCTION

BIOS (Base Input/Output System) - хранится в ПЗУ, запускается при
старте компьютера.

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

Нужна лишь минимальная поддержка устройств:
    Storage	(диски, дискеты, CD-ROM, USB storage)
    Console
    Network (для загрузки с сети [PXE])

BIOS API: что бы система смогла определить параметры и загрузится.

И энергонезависимой памяти для хранения конфигурации [BIOS SETUP]:
    CMOS RAM	[PC]
    NVRAM		[Macintosh]

Типовые настройки BIOS
    Настройки конкретных аппаратных устройств
        Разрешено/запрещено
        Конкретные настройки
    Пароли на вход в CMOS и загрузку системы
    Boot-devices список (с приоритетами)

Почему в PC так много функций в BIOSе управляющих устройствами не
нужними для загрузки?

Тяжелое наследие ROM-BASIC и MS-DOS.
Бывало и хуже: YAMAHA MSX-2.

Следующий шаг - EFI (Extended Firmware Interface).
На HDD в специальной партиции хранятся pre-boot драйверы для устройств,
утилиты для конфигурации. (К сожалению пока только IA-64).

Загрузка BIOS:
    POST	(Power On Self Test)
    Инициализация внешний устройств
    Выбор устройства для загрузки
    Загрузка Boot сектора или boot image.

При включение компьютера запускается POST (Power On Self Test).

Тестируется микропроцессор, затем начинают тестироваться базовые компоненты на
системной плате.

TODO: Award BIOS

Существует 2 принципиальные разницы для bootstrap процессора и для остальных.
Bootstrap процессор после выполнение тестов начинает выполнять инициализацию
оборудования, остальные процессоры останавливают, могут и вообще обесточить через chipset.

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

BIOS проводит инициализайию на PCI шине (адресса для доступа к конфигурационному
адрессному пространству PCI BIOS знает - они жестко прошиты в коде).

Инициализация памяти: инициализируют PCI функцию чипсета: DRAM Controller,
читают информацию о модулях памяти из SPD (Serial present detected).

Происходит Update микрокода в процессоре. Производители процессоров предоставляют
блоки update в бинарном виде производителям материнских плат.

Потом происходит ROMSCAN, (для старых компьютеров это поиск ROM в соответсвующих
областях адрессного пространства, а для новых - адресса ROM назначаются самим же BIOS
для PCI устройств). И для каждого из найденных ROM проверяются соответсвующие сигнатуры
и если все ок - то этому ROM передают управление.
Как правило первым внешним ROM инициализируют ROM видеоадаптера.

Затем как правило предоставляется возможность зайти в SETUP

После SETUP есть возможность войти в меню других ROM

После выхода из всех этих меню BIOS настраивает параметры аппаратуры уже в соответсвии с
настройками которые были в SETUP.

ESCD NVRAM
PnP OS [Yes/No]
    если нет - то BIOS конфигурирует все устройтсва сам

Инициализация закончена, в POST порт записывают значение 00 - равное окончанию инициализации.
И начинается загрузка.

В порядке указанном в SETUP BIOS пытается прочитать с устройства загрузочный сектор
(для жестких дисков - это первый сектор диска, для CD/DVD все определяется по Boot Catalog,
специальной структуре, которая находится в определенной зоне диска.

Если не удалось прочитать - идем к следущему устройству
Если удалось - проверяем сигнатуру 55 AA  по смещению 1FE (даже если сектор длиннее).
Если сигнатуры нет - идем к следущему устройтву
Если же есть передаем управление считанному коду.

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

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

Загрузка OS:
    Первичный загрузчик (Boot сектор или boot image) читает вторичный
    Вторичный
        грузит ядро OS
        грузит драйвера устройств (может только часть)
        грузит конфигурационные файлы OS
        запускает OS

Сервисы BIOS:

API BIOS.
Собственно API BIOS на PC изначально формировались на поддержку ROM BASIC.

    int 10h - Управление видеоадаптером (текстовый и графический режим)
    int 11h - Получение конфигурации оборудование
    int 12h - Запрос размера памяти (старый)
    int 13h	- Дисковая подсистема
    int 14h - Последовательный порт
    int 15h - Системные сервисы
    int 16h - Клавиатура
    int 17h - Паралельный порт
    int 19h - Перезагрузка системы

TODO: Продетализировать

Сервисы EFI:
    TODO: написать какие классы устройств доступны дополнительно
          по сравнению с BIOS
    Файловые системы
    Сетевые адаптеры
    Сетевые протоколы


80.1.2. ДРАЙВЕРЫ

THIS SECTION IS UNDER CONSTRUCTION

Драйвер - программа управляющая устройством или несколькими и имеющая
унифицированный интерфейс с OS.

    +------------+
    |    OS      |
    +------------+
    |   Driver   |
    +------------+
    |  Hardware  |
    +------------+

    +------------+         +-----------+
    |  Driver    |-------+------------+|
    +------------+       |   Device   |+
                 +------------+

Интерфейс зависит от операционной системы и типа устройства.

Например в UNIX устройства бывают символьные и блочные:

    Обмен с блочными устройствами происходит данными фиксированной
    длинны кратной размера блока.
    Типичные запросы к блочным устройствам:
        Взять размер устройства в блоках
        Взять размер блока
        Взять геометрию устройства
        Прочитать блоки
        Записать блоки
        SCSI pass-through (потому что вся storage кроме IDE/ESDI - SCSI)

    Типичные запросы к символьным устройствам
        Чтение
        Письмо
        Управление (ioctl)

    Но все равно некоторые типы устройств имеют специфические интерфейсы
    например FSD - File System Driver.
    Или драйверы сетевых карт и протоколов.

В Windows устройства более специализированные
    SCSI Miniport
    NDIS Miniport
    NDIS Protocol
    Generic Kernel Mode Driver --- Bus Driver
                       FSD Driver
                       Filter Drivers
    WDM  (как правило USB HID)

        Драйверы
           /        \
     Драйвер       Фильтр Драйвер
    физического   (например драйвер класса устройств).
        устройства

TODO: Типовые интерфейсы драйверов

TODO: Типовые API предоставляемые OS для драйверов.

Управление памятью
    Структуры данных и запросы могут находится в различных типах памяти
        OS Non-Paged Pool (Адрессное пространство OS, неподкачиваемое)
        OS Paged Pool     (Адрессное пространство OS, подкачиваемое)
        Application	  (Адрессное пространство приложения)
    Понятно, что драйвер должен уметь осуществлять доступ во все эти
    пространства, при необходимости подкачивать и локировать страницы.
    Хотя бы копировадь данные между kernel и user spaces.

Управление устройствами
    Физический ввод/вывод
    Работа с конфигурационной информацией (PCI Bus итд, Registry)

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

Работа с пространством имен Object Managerа

Вспомогательные сервисы
    Запуск и управление другими драйверами
        Включая их вызовы
    Подсоединение к другим устройствам


80.1.2.1.1. КОНФИГУРИРОВАНИЕ ШИН

THIS SECTION IS UNDER CONSTRUCTION

Одна из основных задач OS обеспечить конфигурирование устройств.
Это состоит из следующих частей:

    1) Найти устройство
    2) Настроить его конфигурацию
       (ресурсы: память, порты ввода/вывода, прерывания).
       (слава богу DMA настраивать не надо - современные устройства Bus Master).

В современных OS это решается следующим образом - существуют драйверы шин (bus driver)
(для большинства hardware с стандартными интерфейсами эти драйверы входят в комплект
операционной системы).

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

Кроме этого OS обеспечивает стандартную прослойку API для общения с драйвером шины,
как правило ориентированную на конкретный тип шины.

Соответсвенно другой вариант - система загружает драйвер, который на старте проверяет
а доступно ли на шине устройство с нужным ему идентификатором или классом.

  Конфигурация PCI

В современных системах все начинается с PCI (или PCI-Express).
Шина PCI кроме обычных пространств памяти и ввода/вывода имеет конфигурационное пространство,
к которому драйвер шины имеет доступ либо через порты ввода/вывода (которые он знает),
либо через BIOS.

То есть и storage (IDE/SATA/SAS) контроллеры, и хост контроллеры для внешних
интерфейсов все сидят на PCI или его потомках.

Формат адресса конфигурационного пространства PCI (один из типов):

В этом адрессном пространстве находятся конфигурационные дескрипторы.
Драйвер шины PCI сканирует это адрессное пространство перебирая Bus и Device
(пользуемся тем,  что у устройства функции должны быть последовательными, т.е. функции 1
не будет если нет функции 0) и читая конфигурайионный дескриптор по данному адрессу.

Формат конфигурационного дескриптора PCI в конфигурационном пространстве PCI:

Поля Vendor ID и Device ID определяют производителя и устройство. То есть по данным
идентификаторам можно однозначно определить устройство.

Например:

VendorID DeviceID  Device
10EC	 8029	   Realtek 8029AS NIC
10EC	 8139	   Realtek 8139A  NIC
1274     1371      Creative SoundBlaster PCI64 Sound card

Если эти поля равны: FFFF и FFFF - это означает что по данному адрессу устройства нет.
Vendor ID описывает производителя, например для Intel Vendor ID = 0x8086

Следущее на что надо обратить внимание это поля Class code/Subclass code/Interface,
они определяют тип устройства.
Некоторые интерфейсы являются стандартными (например PCI IDE controller имеет один и тот
же набор регистров, независимо от того кем он произведен (т.е. разный VendorID/DeviceID,
но устройство по сушеству стандартное).

Ниже приведена краткая таблица классов/сабклассов для PCI устройств:

Class SubClass		Description
            --- Obsolete ----------
0	0		old PCI device
0	1		old PCI VGA
            ---- Storage Adapter --
1	0		SCSI adapter
1	1		IDE  adapter
1	2		FDC  adapter
1	3		IPI  adapter
1	4		RAID adapter
1	0x80		Other storage
            ---- Network Adapter ---
2	0		Ethernet NIC
2	1		Token Ring NIC
2	2		FDDI NIC
2	3		ATM NIC
2	4		ISDN NIC
2	0x80		Other network
            ------- Video Card -----
3	0		VGA
3	1		XGA
3	2		3D-video
3	0x80		Other video
            -------- Multimedia -----
4	0		Videodevice
4	1		Audio
4	2		Phone
4	0x80		Other multimedia
            ------- Memory ----------
5	0		DRAM
5	1		Flash
5	0x80		Other memory
            ------- Bridge ----------
6	0		Host bridge
6	1		ISA bridge
6	2		EISA bridge
6	3		MCA bridge
6	4		PCI-to-PCI bridge
6	5		PCMCIA bridge
6	6		NuBus bridge
6	7		CardBus bridge
6	8		RACEway bridge
6	9		Transparent PCI-PCI bridge
6	0x80		Other bridge
            -------- Ports ------------
7	0		COM port
7	1		LPT port
7	2		Multiport
7	3		Modem
7	0x80		Other comm
            -------- System -----------
8	0		PIC
8	1		DMA
8	2		Timer
8	3		RTC
8	4		Hot plug PCI
            ------------ Input --------
9	0		Keyboard
9	1		Digitizer
9	2		Mouse
9	3		Scanner
9	4		Game port
9	0x80		Other input device
            ---------- Docking --------
0xa	0		Docking Station
            ---------- Processor ------
0xb	0		386
0xb	1		486
0xb	2		Pentium
0xb	0x10		Alpha
0xb	0x20		PowerPC
0xb	0x30		MIPS
0xb	0x40		coprocessor
            -------- Ext. Buses -------
0xc	0		IEEE1394 (FireWire)
0xc	1		ACESS.bus
0xc	2		SSA
0xc	3		USB
0xc	4		Fibre Channel
0xc	5		SMbus
            ---------- InfraRED -------
0xd	0		IRDA
0xd	1		IR-controller
0xd	0x10		RF-controller
            ----------- I2O -----------
0xe	0		I2O
            ---------- Multimedia -----
0xf	1		TV adapter
0xf	2		Audiocontroller
0xf	3		Voice adapter
            --------- Security --------
0x10	0		Crypter/decrypter (network/computer)
0x10	0x10		crypter/decrypter (game)
            -------- Signals ----------
0x11	0		DPIO module
0x11	0x80		other signals processors

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

Следущее на что надо обратить внимание - это ресурсы. PCI позволяет конфигурировать
Базовые адресса для регионов памяти (в том числе и 64-бит, если конечно устройство это
поддерживает), портов ввода/вывода и прерываний.

Все вы видели в BIOS настройку:
    PnP OS Enable: Yes/No
Если No, то всю настройку адрессов делает BIOS, в противном случае (Yes) система может
переконфигурировать как ей удобно (и как правило сохранить в специальной энергонезависимой
памяти)

А что было до PCI?
ISA PnP, EISA и MCA имели определенные конфигурайионные возможности
TODO: Расписать позднее

А до этого были Legacy devices на ISA шине в которых конфигурация задавалась аппаратно
(как правило путем установки переключателей или набора джамперов на печатной плате),
в результате была масса трудноуловимых проблем с конфликтами по адрессам, каналам DMA
и прерываниям).
Кроме того - одна из самых больших проблем это определение устройств драйверами,
как правило определение сводилось к тому что с строго определенными адрессами портов
на которые могло садиться устройство производились магические опреации ввода/вывода:

Например детектирование Creative Sound Blaster производилось так
(немного упрощенный вариант):

Базовые порты для этой аудиокарты:
    0x210	0x200	0x230	0x240	0x250	0x260

    Записать в порт BASE+6 значение 1
    Записать в порт BASE+6 значение 0
    50 раз повторять:
        Читать из порта BASE+14
        Если старший бит этого чтения = 1 то перестать повторять
    Если чтение из порта BASE+10 возвратило 0xAA то это Sound Blaster 16
    В противном случае это не Sound Blaster

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

Типовые запросы к PCI driver Bus, или к операционной системе по конфигурации PCI:

    - Найти N-е вхождение устройства с заданным VendorID/DeviceID
        возвращает адресс в PCI configuration space
    - Hайти N-е вхождение устройства с указанным классом.
    - Читать/Писать конфигурационное пространство для устройства

Таким образом PCI это основа для конфигурирования современного компьютера.

Дальнейшая конфигурация производиться уже драйверами устройств (для PCI), которые
являются драйверами других шин (например USB).
Рассмотрим вкратце как это происходит:

  Конфигурация USB

Драйвер шины USB находит USB PCI Host контроллеры по классу:

Class  Sub  Iface   Controller
0C     03    00	      UHCI   (USB 1.0)
0C     03    10	      OHCI   (USB 1.0)
0C     03    20	      EHCI   (USB 2.0)

Опрашивая порты корневого хаба драйвер узнает подсоеденино ли устройство к
данному порту, а также является ли устройство High Speed.
После этого драйвер разрешает порт и делает запрос SET_ADDRESS который присваивает
индекс по которому данное устройство будет в дальнейшем откликаться на запросы.

Затем делается запрос GET_DESCRIPTOR c параметром получения Device Descriptor.
Результатом служит Device Descriptor:

Интересующие нас поля с точки зрения конфигурации:
VendorID/DeviceID - однозначно определяют устройство
(Имейте в виду это USB идентификаторы - они отличаются от PCI).

А так же Class/Subclass/Protocol.

 ---------------------------------------------------------------------------
Class	Subclass	Description
 ---------------------------------------------------------------------------
00	--              Undefined (Class information is at intrerface level)
01	--		Audio
02	--		Communication-Control
    01		Direct Line control
    02		Abstract Line control
    03		Telephone Line control
    04		Multi-channel Line control
    05		CAPI
    06		Ethernet
    07		ATM
03	--		HID
    01	--	Boot devices
        01	Keyboard
        02	Mouse
06	--		Image
07	01		Printer
08	--		Mass-storage devices
    01			generic (disk)
    02			CD/DVD
    03			Tape
    04			UFI (removable)
    05			SFF-8070i (removable)
    06			SCSI transparent command set
09	--		USB Hub
0B	--		Smart-Card
0D	--		Content-security
E0	--		Wireless controller
FF	--		Vendor specific
 ---------------------------------------------------------------------------

HID подклассы:

---------------------------------------------------------------------
Subcls  Protocol	Description
---------------------------------------------------------------------
01	--		Generic Desktop
    01			input
    02			mouse
    04			joystick
    05			game pad
    06			keyboard
    07			key pad
02	--		Simulation control
    01			flight simulation device
    02			automobile simulation device
03	--		Virtual reality control
    01			belt
    02			body suit
    03			flexor
    04			glove
    05			head tracket
    06			head mounted display
    07			hand tracker
04	--		Sport control
05	--		Game control
    01			3D game controller
    02			pinball device
    03			gun device
---------------------------------------------------------------------

Если устройство оказывается USB Hub, то оно дополнительно конфигурируется и
затем происходит конфигурирование каждого из его портов.

TODO: подробнее

К счастью для USB устройства ресурсы не нужны, так как оно работает через
USB Host controller (у которого есть свои порты ввода/вывода и прерывания).

  Конфигурирование SCSI

Драйвер SCSI шины (SCSI miniport) сбрасывает SCSI шину, затем начинает сканирование
шины выдавая по каждому адрессу SCSI команду INQUIRE, по которой устройство (если оно
конечно есть) возвращает информацию:

Наиболее интересное поле - это DeviceType

DeviceType	Description
00		Direct Access Device (Disk)
01		Sequental Access Device (Tape)
02		Printer Device
03		Processor Device
04		WORM Device
05		CD/DVD/BR
06		Scanner device
07		Optical device
08		Changer device
09		Communication device

Кроме того VendorID/DeviceID определяют устройство.
Примеры работы INQUIRE:

HP DVD Writer 200i (ATAPI DVD+RW):
****************************************************************************
*     Inquiry data
****************************************************************************
* 0000: 05 80 00 32 45 00 00 00 48 50 20 20 20 20 20 20   ...2E...HP
* 0010: 44 56 44 20 57 72 69 74 65 72 20 32 30 30 6A 20   DVD Writer 200j
* 0020: 31 2E 30 36 30 32 30 33 31 32 00 00 00 00 43 4E   1.06020312....CN
* 0030: 32 33 52 31 31 32 36 4A FF FF 52 49 43 44 41 32   23R1126J..RICDA2
* 0040: 34 30 30 34 35 36 32 20                           4004562
****************************************************************************
*************** INQUIRY data ***************
00000000 : byte        05 Perepherial device type/qualifier
            * CD/DVD
00000001 : byte        80 Removable (high bit)
00000002 : byte        00 Version
00000003 : byte        32 Interface depended field
00000004 : byte        45 Additional data length
00000005 : dump  (0003)  Interface depended field
00000005 :  00 00 00                                         [...-------------]
00000008 : dump  (0008)  Vendor ID
00000008 :  48 50 20 20 20 20 20 20                          [HP      --------]
00000010 : dump  (0010)  Produce ID
00000010 :  44 56 44 20 57 72 69 74 65 72 20 32 30 30 6A 20  [DVD Writer 200j ]
00000020 : dump  (0004)  Produce revision level
00000020 :  31 2E 30 36                                      [1.06------------]

Iomega ZIP 100 (ATAPI Removable):
------------------------------------------------------------------------------
00000000: 00 80 00 01 75 00 00 00 49 4f 4d 45 47 41 20 20   [ _ .u   IOMEGA  ]
00000010: 5a 49 50 20 31 30 30 20 20 20 20 20 20 20 20 20   [ZIP 100         ]
00000020: 32 33 2e 44 30 34 2f 32 32 2f 39 37 00 00 00 00   [23.D04/22/97    ]
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   [                ]
00000040: 00 00 00 00 00 00 00 00                           [                ]
------------------------------------------------------------------------------
*************** INQUIRY data ***************
00000000 : byte        00 Perepherial device type/qualifier
            * Disk
00000001 : byte        80 Removable (high bit)
00000002 : byte        00 Version
00000003 : byte        01 Interface depended field
00000004 : byte        75 Additional data length
00000005 : dump  (0003)  Interface depended field
00000005 :  00 00 00                                         [...-------------]
00000008 : dump  (0008)  Vendor ID
00000008 :  49 4F 4D 45 47 41 20 20                          [IOMEGA  --------]
00000010 : dump  (0010)  Produce ID
00000010 :  5A 49 50 20 31 30 30 20 20 20 20 20 20 20 20 20  [ZIP 100         ]
00000020 : dump  (0004)  Produce revision level
00000020 :  32 33 2E 44                                      [23.D------------]

IBM DSAS-3540 (SCSI-2 Harddisk):
------------------------------------------------------------------------------
00000000: 00 00 02 02 8f 00 00 1a 49 42 4d 20 20 20 20 20   [  .._  .IBM     ]
00000010: 44 53 41 53 2d 33 35 34 30 20 20 20 20 20 20 20   [DSAS-3540       ]
00000020: 53 34 37 4b 51 33 30 32 39 35 31 38 20 20 20 20   [S47KQ3029518    ]
00000030: 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00   [                ]
00000040: 00 00 00 00 00 00 00 00                           [                ]
------------------------------------------------------------------------------
*************** INQUIRY data ***************
00000000 : byte        00 Perepherial device type/qualifier
            * Disk
00000001 : byte        00 Removable (high bit)
00000002 : byte        02 Version
00000003 : byte        02 Interface depended field
00000004 : byte        8F Additional data length
00000005 : dump  (0003)  Interface depended field
00000005 :  00 00 1A                                         [...-------------]
00000008 : dump  (0008)  Vendor ID
00000008 :  49 42 4D 20 20 20 20 20                          [IBM     --------]
00000010 : dump  (0010)  Produce ID
00000010 :  44 53 41 53 2D 33 35 34 30 20 20 20 20 20 20 20  [DSAS-3540       ]
00000020 : dump  (0004)  Produce revision level
00000020 :  53 34 37 4B                                      [S47K------------]

THIS SECTION IS UNDER CONSTRUCTION

TODO: КОнфигурирование PnP Serial & Parallel Port devices.


80.1.2.1.1.1. PnP КОНФИГУРИРОВАНИЕ

THIS SECTION IS UNDER CONSTRUCTION

  PnP конфигурирование

Как происходит PnP конфигурирование в современных OS.

Драйвер шины рапортует что он нашел устройство и возвращает его
идентификаторы. По этим идентификатором OS находит и загружает драйвер
этого устройства.

Далее для Windows:

Вызывается функция AddDevice(), которая создает объект данного instance устройства.
Устройство пока неактивно.

После этого PnP Manager начинает договариваться о Hardware ресурсах.

Ресурсы включают в себя:
    1) Порты ввода/вывода
    2) Области памяти (естественно физической)
    3) Прерывания
    4) DMA каналы (если используются)

Все происходит в 3 стадии:

A) Операционная система спрашивает список возможных ресурсов
   Драйвер отвечает

Затем операционная система пытается распределить ресурсы между различными
устройствами, в процессе OS переодически

B) вызывает драйвер с списком предлагаемого варианта ресурсов
   Драйвер может согласиться, может отказаться

OS продолжает делать подбор пока все драйверы не согласяться, или пока ей это не надоест,
при этом пункт (B) может быть проделан многократно.
Когда OS закончит:

С) вызывает драйвер с нотификацией об окончательных ресурсах

D) Вызывает команду START_DEVICE в драйвере
   Драйвер запускает устройство
   Устройство начинает работать.

  PnP управление устройствами

Удаление устройства:
        Идет запрос  QUERY_REMOVE_DEVICE
    Если не все согласились то отменяем
        запросом CANCEL_REMOVE_DEVICE
    Если же все согласились то
        REMOVE_DEVICE

Неожиданное удаление устройства:
    SURPRISAL_REMOVE
    REMOVE_DEVICE

Переконфигурация устройства:
    Идет запрос QUERY_STOP_DEVICE
    Если не все согласились то отменяем
        CANCEL_STOP_DEVICE
    Если все согласились то STOP_DEVICE
    (Переконфигурирум ресурсы как описано выше,
     когда закончили снова START_DEVICE)

Почему устройства могут несоглашаться на остановку или удаление?
Например на устройстве может быть page file, или система,
или залоченные файлы, итд.

Запрос на связи устройств:
    QUERY_DEVICE_RELATIONS

Устройства бывают связанными друг с другом (например партиция связана с диском,
PCI устройство связано с PCI шиной, и что бы правильно управлять PnP система
должна знать кто-от-кого зависит. Такие запросы помогают ей это выяснить.

  Управление энергопотреблением

Уровни энергопотребления:

    Working
    Sleeping1
    Sleeping2
    Sleeping3
    Hibernate
    Shutdown

Типовые запросы:

    Запрос поддерживаемых состояний энергопотребления
    Запрос текущего состояния энергопотребления
    Запрос возможен ли безопасный переход в указанное состояние
    Запрос перехода в указанное состояние

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


80.1.2.1.2. РАБОТА ДРАЙВЕРОВ С ПРЕРЫВАНИЯМИ

THIS SECTION IS UNDER CONSTRUCTION

Уровни приоритета работы с OS

    IPC-INTERRUPT
    HW-INTERRUPT
    PAGING		на этом уровне идет подкачка станиц не присутсвующих в памяти
    APC
    PASSIVE

Практически каждое нижнеуровневое устройство (PCI-based) имеет прерывания.

Количество прерываний ограничено и даже сейчас для PC с переходом от PIC к APIC
ситуация улучшилась лишь немного. Кроме того стандарнтная PCI шина имеет только 4
линии запроса прерываний, поэтому устройства должны шарить прерывания.

Когда приходит прерывание оно как правило сваливается в OS, которая вызывает
соответсвующие зарегистрированные обработчики прерывания из драйверов.

Что должно делать драйвер устройства когда он получил прерывание?
    1) Проверить является ли его устройство источником этого прерывания
       (как правило для этого надо прочитать соответсвующие регистры устройства)
       И если нет быстро вернуть управление OS, которая будет уже дергать
       следующих обработчик прерываний

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

Зачем нужны DPC функции - проблема в том что прерывание приходит достаточно неожиданно,
а для обработки данных надо обращаться к структурам драйвера и/или операционной системы,
а что если к ним еще кто-то в этот момент обращается, а прерывание ждать не может,
поэтому планируется callback.

Прерывания бывают по фронту и по уровню

По фронту:

В этом случае легко потерять прерывание

по уровню:

В случае shared прерывания (которое разделяется между несколькими устройствами)
устройство должно еще сказать - не оно ли источник прерывания.

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

  Синхронизация с обработчиками прерываний

Если есть данные доступ к которым расшарен между кодом и обработчиком прерывания.
Применяются специальные средства.

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

KIRQL
  KeAcquireInterruptSpinLock(
    IN PKINTERRUPT  Interrupt
    );

VOID
  KeReleaseInterruptSpinLock(
    IN PKINTERRUPT  Interrupt,
    IN KIRQL  OldIrql
    );

Вариант, который вызывает функцию в контексте безопасном с точки зрения
синхронизации с обработчиками прерывания.

// Windows Kernel Mode

BOOLEAN
  KeSynchronizeExecution(
    IN PKINTERRUPT  Interrupt,
    IN PKSYNCHRONIZE_ROUTINE  SynchronizeRoutine,
    IN PVOID  SynchronizeContext
    );

THIS SECTION IS UNDER CONSTRUCTION


80.1.2.1.3. РАБОТА ДРАЙВЕРОВ С ПАМЯТЬЮ

THIS SECTION IS UNDER CONSTRUCTION

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

Поэтому мы имеем следущие варианты памяти:

Type		Space		Pagable       ProcessDependable
 ---------------------------------------------------------------
Virtual         User		Pagable       Yes
Virtual		Kernel		Pagable       No
Virtual		Kernel		NonPageable   No
Physical	None		None          No
 ---------------------------------------------------------------

Соответвенно драйвер должен это учитывать.

Пользователь дает запрос к драйверу с памятью отмапированной в User space.
Более того она привязана к конкретному процессу, если scheduler сменит процесс
то эти адресса будут указывать в никуда.

Другой драйвер дает запрос c памятью отмапированной в Kernel space.
Она может быть paged (то есть страницы могут отсутсвовать в памяти),
может быть non-paged.

Например если структура данных должна быть доступна для обработчика прерывания
она должна быть non-paged, потому что подкачка невозможна в этот момент.
Тоже самое для storage драйверов - потому что подкачка невозможна когда обрабатывается
другой запрос по подкачке.

А DMA устройства интересует physical память.

В ранних операционных системах проблему решали путем двойной буферизации,
копируя буфер из пользовательской памяти в системную и/или наоборот,
в зависимости от запроса.

Современные OS активно используют страничную память, а современное железо в
состоянии выполнять scatter/gather DMA, поэтому как правило данные лишний раз
не копируют, а используют внутренние структуры, которые содержат отображения
виртуальных страниц на физическую память.

На самом деле все зависит от запроса, мапирование памяти как правило приводит к
сбросу TLB caches, что занимает время, поэтому часто если запрос небольшой длинны
(например меньше страницы), часто имеет смысл просто скопировать данные в промежуточный
буфер - это будет быстрее чем мапировать память.

Пример такой структуры - это MDL (Memory Description List) в Windows:

Но не всегда это возможно, типовые проблемы:

1) Невыровненный запрос
   Дело в том, что современные Bus-Master DMA устройтва как правило физически не способны
   передавать данные которые не выравнены на определенную границу (как правило 4 байта).
   За счет отсутствия такой поддержки сильно упрощается логика аппаратных схем.
   И если от пользователя пришел невыровненный запрос, то системе приходится заниматься
   его буфферизацией через системный буфер, который выравнен.

   Поэтому одно из свойств устройства - это выравнивание

2) Устройство не поддерживающее полное адрессное пространство.
   Например 32-бит PCI карта на компьютере с 8GB памяти,  или ISA карта на компьютере
   с памятью > 16MB.
   В этом случае возможна ситуация когда данные которые хотят передать находяться
   в физической памяти, которая находиться за пределами адрессного пространства устройства,
   и как результат операйионной системе приходится буферизировать эти данные в одном
   из нескольких "нижних" буферов, которые операционная система резервирует при старте,
   специально для таких целей.


80.1.2.1.4. РАБОТА ДРАЙВЕРОВ С ПРОСТРАНСВОМ ИМЕН И ИНФРАСТРУКТУРА

THIS SECTION IS UNDER CONSTRUCTION

Принцип UNIX - все есть файл, лежит в основе современных операционных систем.
Существует два основных подхода:

1) UNIX подход
   Устройство характеризуется числами major_device_number.minor_device_number
   Для соответствия именам файлов в файловой системе используются так называемые
   device files, которые используются для редирекции

2) Полный подход (например Windows или QNX)
   Когда имеется специальное пространство имен object manager или resource manager
   или как его не назови, через которое можно получить доступ к объекту устройства
   по имени

  Windows

После того как драйвер запустили (или вызвали AddDevice) он создает объект устройства
который связан с объектом драйвера (использует системную функцию IoCreateDevice).
При создание объекту устройство можно дать имя (как правило используют для storage devices),
или возложить эту функцию автоматически на device manager.
Так же задается при создании тип устройсва (например FILE_DEVICE_DISK), а так же
его характеристики (важно в основном для Storage устройств).

Объект драйвера содержит таблицу указателей на функции это драйвера:

    IRP_MJ_CREATE			открывает устройство
    IRP_MJ_CLOSE			закрывает устройство
    IRP_MJ_CLEANUP			говорит о том что надо удалить все запросы связанные
                    с конкретным открытием устройства, потому что все объекты
                    закрыты
    IRP_MJ_READ			читает с устройства
    IRP_MJ_WRITE			пишет на устройство
    IRP_MJ_DEVICE_CONTROL		интерфейс IOCTL
    IRP_MJ_FILE_SYSTEM_CONTROL      интерфейс IOCTL для драйверов файловой системы
    IRP_MJ_INTERNAL_DEVICE_CONTROL	специальный системный IOCTL
                    (обычно используется для SCSI или USB устройств)
    IRP_MJ_QUERY_INFORMATION	Запрашивает информацию
    IRP_MJ_SET_INFORMATION		Устанавливает информацию
    IRP_MJ_PNP
    IRP_MJ_POWER
    IRP_MJ_SYSTEM_CONTROL		WMI итд
Остальные IRP_MJ функции относяться в основном к драйверам файловых систем.

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

  UNIX

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

Например для Linux:
 ----------------------------------------------------------------
 Major		Minor
 ----------------------------------------------------------------
 1 char	Memory devices
          1 = /dev/mem		Physical memory access
          2 = /dev/kmem		Kernel virtual memory access
          3 = /dev/null		Null device
          4 = /dev/port		I/O port access
          5 = /dev/zero		Null byte source
          6 = /dev/core		OBSOLETE - replaced by /proc/kcore
          7 = /dev/full		Returns ENOSPC on write
          8 = /dev/random	Nondeterministic random number gen.
          9 = /dev/urandom	Faster, less secure random number gen.
         10 = /dev/aio		Asynchronous I/O notification interface
         11 = /dev/kmsg		Writes to this come out as printk's
         12 = /dev/oldmem	Used by crashdump kernels to access
                    the memory of the kernel that crashed.
 ----------------------------------------------------------------
 2 block	Floppy disks
          0 = /dev/fd0		Controller 0, drive 0, autodetect
          1 = /dev/fd1		Controller 0, drive 1, autodetect
          2 = /dev/fd2		Controller 0, drive 2, autodetect
          3 = /dev/fd3		Controller 0, drive 3, autodetect
        128 = /dev/fd4		Controller 1, drive 0, autodetect
        129 = /dev/fd5		Controller 1, drive 1, autodetect
        130 = /dev/fd6		Controller 1, drive 2, autodetect
        131 = /dev/fd7		Controller 1, drive 3, autodetect

        To specify format, add to the autodetect device number:
          0 = /dev/fd?		Autodetect format
          4 = /dev/fd?d360	5.25"  360K in a 360K  drive(1)
         20 = /dev/fd?h360	5.25"  360K in a 1200K drive(1)
         48 = /dev/fd?h410	5.25"  410K in a 1200K drive
         64 = /dev/fd?h420	5.25"  420K in a 1200K drive
         24 = /dev/fd?h720	5.25"  720K in a 1200K drive
         80 = /dev/fd?h880	5.25"  880K in a 1200K drive(1)
          8 = /dev/fd?h1200	5.25" 1200K in a 1200K drive(1)
         40 = /dev/fd?h1440	5.25" 1440K in a 1200K drive(1)
         56 = /dev/fd?h1476	5.25" 1476K in a 1200K drive
         72 = /dev/fd?h1494	5.25" 1494K in a 1200K drive
         92 = /dev/fd?h1600	5.25" 1600K in a 1200K drive(1)
 ----------------------------------------------------------------
 8 block	SCSI disk devices (0-15)
          0 = /dev/sda		First SCSI disk whole disk
         16 = /dev/sdb		Second SCSI disk whole disk
         32 = /dev/sdc		Third SCSI disk whole disk
            ...
        240 = /dev/sdp		Sixteenth SCSI disk whole disk

        Partitions are handled in the same way as for IDE
        disks (see major number 3) except that the limit on
        partitions is 15.
 ----------------------------------------------------------------

В системе (как правило в директории /dev находяться специальные файлы устройств,
которые имеют major:minor номера соответсвующие устройствам. Если нет нужного
файла его можно создать.

А дальше файл просто открывается.


80.1.2.2.1. STORAGE DRIVERS

Подсистема storage

Основа - блочные устойства разных уровней

    блочное устройство низкого уровня покрывает физическое устройство
    например IDE диск, или SCSI CD-ROM

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

    На съемных носителях устройство тома остается, а данные могут меняться
    Основные проблемы: сменный носитель с более чем одной партицией
    Multisession CD - какую сессию брать
        DOS берет первую
        Windows XP берет последнюю
        Есть системы где можно выбрать какую

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

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

    Драйвер класса устройства
        пример: Disk Class Driver
        поддерживает общий блочный интерфейс + специфические запросы
        для данного типа устройств:
        например: Read TOC и Play Audio для CD/DVD носителей
        Как правило опирается на более низкоуровневвые драйверы специфичные к
        интерфейсу - например на IDE или SCSI miniportы, USB или FireWire storage
        class драйверы. Но тем не менее для нестандартных устройств (например
        LPT ZIP драйв - может быть полностью реализован здесь.
        Как правило драйвер класса поддерживает SCSI PassThrough для SCSI устройств.

    Низкоуровневые драйверы специфичные к интерфейсу:
        SCSI miniport
        Поскольку большая часть storage устройств (если это не IDE),
        построена на основе SCSI команд.

        Основные Запросы к такому драйверу:
            Сбросить SCSI шину
                Выполнить SCSI команду
                CDB (Command Description Block) - SCSI команда (6-16 байт)
                Направление куда пересылать данные (в host, из hosta)
                Буфер для данных
                Максимальный размер буфера
                Буфер куда будет записан SCSI Sense в процессе выполнения операции

        IDE miniport
        Осуществляет IDE запросы
        Запросы к такому драйверу
            Сброс IDE шины
            Выполнить IDE команду
                Блок IDE регистров
                Направление куда пересылать данные (в host, из hosta)
                Буфер для данных
                Максимальный размер буфера

    Промежуточные слои могут портить жизнь.
    Например Windows 2000. Max размер у диска в байтах поддерживаемый OS = 2^64
    Новый SCSI контроллер поддерживающий посылку 16-байтных SCSI команд
    SCSI Disk Array - который показывает себя как 5TB жесткий диск
    Система видит только 2TB жесткий диск
    Потому что SCSIlizer который преобразует запросы типа Read/Write/etc в SCSI команды
    в Windows 2000 понятие не имеет что есть 16-байтные SCSI команды и как следствие
    диски такого объема

    Для устройств находящихся на внешних шинах есть лишний уровень иерархии
    Например для USB:
        Disk Class Driver
        USB Storage Class Driver (обслуживает storage устройства)
        USB Bus Driver (USB Host controller)

TODO: Примеры интерфейсов драйверов


80.1.2.2.2. FILESYSTEM DRIVERS

Подсистема Filesystem

Традиционно два типа функциональности
        FSR (File System Recognizer)
        Вызывается системой в случае получения нотификации о том что новое storage устройство
        поднялось (или носитель вставили)
        Задача: Определить находиться ли на устройстве определенная файловая система, и если да
        то загрузить (или нотифицировать) FSD.

        Бывают и промежуточные уровни - например Volume Tracker
        Например старые дисководы не имели флага о том что диск менялся
        Поэтому какой конкретно том в носителе стоит определял Volume Tracker на основании
        Volume Serial Number.

        FSD (File System Driver)
        Драйвер файловой системы - осуществляет низкоуровневую часть операции с файлами
        на конкренной файловой системе.
        Как правило в большинство систем его функциональность разделена на 2 группы:
        Volume Operations (vfsnode) - Mount/Get Statistics (Size/Free space)/etc
        FsObjects Operation (vnode) - Работа уже с файлами и директориями

        File System Filter
        Антивирусы итд

TODO: Примеры интерфейсов драйверов


80.1.2.2.3. NETWORKS DRIVERS

Архитектура:

    Socket Driver
    Содержит поддержку интерфейса socket для конкретного семейства протоколов
    (может не быть драйвером, а быть встроенным в OS).

    Network Protocol
    Драйвер отвечающий за конкретное семейство сетевых протоколов (например IPv4, IPv6, IPX,
    NetBEUI, итд). Собственно он реализует все базовые протоколы и схемы взаимодействия для
    конкретного семейства протоколов. Кроме того он содержит Routing table для семейства
        протоколов.

    Код специфичный для конкретного низкоуровневого сетевого окружения например для
    Etherne, TokenRing или ATM. Как правило встроен в операционную систему.

    Network Miniport
    Драйвер самого нижнего уровня, который занимается тем, что
    принимает и отсылает сетевые frames на конкретном оборудовании.
    В настоящее время идет тенденция к повышению производительности таких
    драйверов за счет - возможности получения и отправки по несколько сетевых
    frames за один запрос, а так же использования scatter/gather буфферов.
    Типичные запросы
        Установить режим драйвера
        Отправить frame
        (Получить frame)
        Установить таблицу Multicast адрессов
        Получить статистику (включая MAC адресс)
        (Установить Mac address)
    Для Connection-oriented окружений
        Установить соединение
        Разъединить

    Network Intermediate
    Специфияный для Windows NT драйвер, который показывал протоколам, что он miniport,
    а miniportу, что он протокол, и весь траффик шел через него, в результате чего
    драйвер мог делать фильтрацию траффика

    Network Filtering Drivers
    Находятся как правило на уровне паралельном драйверам протоколов, содержат средства
    для фильтрации трафика. Могут находиться и ниже.

TODO: Примеры интерфейсов драйверов различного уровня


80.1.3. ОПЕРАЦИОННЫЕ СИСТЕМЫ

THIS SECTION IS UNDER CONSTRUCTION

Объекты операционных систем:
    Устройства	(объекты ядра)
    Процессы	(адрессное пространство, ресурсы)
        единица выделения ресурсов
    Потоки		(квантуются)
        единица исполнения
    Файлы
    Терминалы       (экранная группа)
    Объекты синхронизации (семафоры, мьютексы)
    IPC
    итд.

Основные задачи OS:
    Scheduling  (квантование времени) [Multiprocessing]
    Виртуальная память и подкачка
    Разграничение доступа
        Authentication
        Athorisation
        ACL
            Обект
            Субъект
                User
                SYSTEM
                Computer
            Права доступа
    Борьба с взаимоблокировками за ресурсы
    Поддержка IPC (Interprocess Communication)
        Семафоры
        Мьютексы
        Мониторы
        Kernel Messages
        Барьеры
        Spin-Lock
            активное ожидание
    Планирование и оптимизация ввода/вывода
        Кэширование
        Приоритезирование (Elevator,Ближайший).
    Поддержка файловых систем
        Shared Files
        Memory-mapped files
    Управление энергопотреблением

    Предоставление API пользовательским приложениям

Основные современные OS:

 ------------------------------------------------------
Платформа	OS			Vendor
 ------------------------------------------------------
x86		MS-DOS			Microsoft
        Windows 3.x		Microsoft
        Windows 9x/ME		Microsoft
        Windows NT/2K/XP/2003	Microsoft
        Linux			*
        FreeBSD			Berkeley university
        NetBSD			Berkeley university
        OpenBSD			Berkeley university
        OS/2, OS/2 eCS		IBM
        BeOS, Zeta              Be
        QNX                     QNX
        Solaris	x86		Sun
        SCO OpenServer		SCO
        UNIXware		SCO
        Netware			Novell
 ------------------------------------------------------
Mac		MacOS			Apple
        MacOS X			Apple
        Linux			*
        FreeBSD                 Berkeley university
 ------------------------------------------------------
Alpha		Digital UNIX		HP
        OpenVMS			HP
        Tru64 UNIX		HP
        Windows NT		Microsoft
        OpenBSD			Berkeley university
 ------------------------------------------------------
Itanium		Windows  XP/2003	Microsoft
        Linux			*
        Tru64 UNIX		HP
 ------------------------------------------------------
Silicon		IRIX			Silicon Graphics
 ------------------------------------------------------
HP		HP-UX			HP
 ------------------------------------------------------
RS/400		AIX			IBM
        Linux                   *
 ------------------------------------------------------
Sun		Solaris			Sun
        Linux                   *
        BSD                     Berkeley University
 -------------------------------------------------------

User
Kernel
Interrupt

Микроядро	- асинхронные взаимодействия
          нити в ядре вытесняются другими
          в микроядре только приметивы
            IPC
            basic scheduling
            Memory management (может быть снаружи)

Монолит		- синхронные взаимодействия
          нити в ядре не вытесняются (только interrupt)
          Расставлять критические секции - это исскуство


80.1.3.1. НИТИ И МНОГОЗАДАЧНОСТЬ

THIS SECTION IS UNDER CONSTRUCTION

Структура нити - что она в себе содержит?

    Контекст (регистры процессора)
    Состояние нити

    TID (Thread ID)
    PID (Process ID которому принадлежит нить)

    Wait Status
    Список объектов которые нить ждет
    Счетчик критических секций

    Localization info

    Время проведенное в режиме ядра
    Время проведенное в пользовательском режиме
    Стартовый адресс нити

TO BE CONTINUED

  Многозадачность

Пседопараллелизм	(на одном CPU)
Мультипроцессор

Многозадачность
    Кооперативная
        программа сама вызывает функцию смены задачи
            Yield()  или GetNextEvent() [Win16]
    Вытесняющая (preemptive)
        по таймеру снимают задачу когда она выработает свой квант времени

  Контекст нити

Контекст нити/процесса (зависит от терминологии в OS)
    Регистры	(IP, stack, GPR, Flags)
    Virtual Memory control registers
           Варианты уменьшить размер контекста
            TS флаг в x86

Смена контекста - дорогая операция
Почему у MMX регистры теже что и в FP? Из-за контекста

У каждой нити свой stack

  Состояния нити

Состояния нитей
    New
    Ready
    Running
    Wait  (Blocked)
    Ready+Paused
    Wait+Paused
    Terminating

  Процессы и потоки

  Планировщик

  Перепланировка

Большинство задач не доживают свой квант

Перепланировка

  Планировка с приоритетами

Планировщики с приоритетами
    Классы планирования
        Real-Time
        Shared-Time

Динамическая приоритезация для Shared-Time:
Повышение приоритета задачам которые зависли на вводе/выводе
или на подкачке.
Снижение приоритета задачам отработавшим полный квант

  Стратегии планирования

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

Задачи:

  FCFS

FCFS (First Come First Serving):

Обрабатываются в том порядке в каком поступили
Проблемы: Длинные задания задерживают всех кто дальше в очереди

  RR

RR (Round Robin):

Каждый процесс получает фиксированный временной слот *квант*
Ротация между готовыми процессами

Выбор кванта
    Слишком короткий - много времени уходит на смену контекста
    Слишком длинный  - медленный ответ на интерактивные запросы
типичный размер кванта 10-100 ms

SRR (Selfish Round Robin):

  FB

FB (FeedBack):

ExpFB:

  SPN

SPN (Shortest Process Next):

иногда называют SJF (Shortest Job First)

Версия для вытесняющей многозадочности:
    SRTF (Shortest Remaining Time First)
Проблемы: как узнать кто более короткий

  Lottery

Каждому процессу дают лотерейные билеты
Каждый квант генерирует номер билета
Процесс получает n/m, где n - кол-во тикетов у процесса, m-общее число тикетов
(Процессы могут обмениваться тикетами)
(Клиеты могут передавать серверу)

  Policy

Процессам присваиваются приоритеты

Например у одного usera - приоритет 40%, у другово 20%,
Машинное время будет делиться между ними согласно приоритетам


80.1.3.1.1. REAL TIME SCHEDULING

Real-time scheduling

  EDF

EDF (Earliest Deadline first)

  LSF

LSF (Least Slack First)

  LST

LL/LST (Least Laxity, Least Slack Time First)

  RMS

RMS (Rate Monotonic Scheduling)

QoS для RTOS


80.1.3.2. ПРОЦЕССЫ И УПРАВЛЕНИЕ ВИРТУАЛЬНОЙ ПАМЯТЬЮ

THIS SECTION IS UNDER CONSTRUCTION

ПРОЦЕССЫ

Процесс - это в первую очередь владелец ресурсов:
       памяти
       объектов (файлов итд)

  Структура процесса

Из чего вообще состоят структуры связанные с процессами в современных OS?

    PID (Process ID)
    PID родителя
    Состояние процесса (в общем то всех интересует зомби ли он или нет)
    Указатели на структуры управления памятью

    Affinity Mask (показывает на каких процессорах процесс может выполняться)
    (особенно полезно для архитектур типа ccNUMA).
    Идеальный процессор для выполнения

    Класс приоритета процесса (как правило, Idle, Normal, Runtime)
    Базовый приоритет процесса
    Размер кванта времени

    Указатели на дескрипторы файлов
    Текущий каталог
    Терминал ассоциированный с процессом

    Структуры связанные с обработкой внешних событий
        Для UNIX систем - таблицы обработчиков сигналов и принятые сигналы
        Для Windows систем - LPC ports (exceptions, debug)

    Quotes (Ограничения)
        на размер адрессного пространства процесса
        на количество процессорного времени
        на размер стека
        на размер кучи
        на количество locked memory
        максимальный размер рабочего набора процесса

    Security связанный с процессом
        Для UNIX систем: Effective UID, Effective GID
        Для Windows систем: Token доступа

    Статистика
        Текущий размер виртуальной памяти используемой процессом
        Пиковый размер виртуальной памяти используемой процессом
        Время выполнения в режиме ядра
        Время выполнения в пользовательском режиме

    Startup information
        Имя программного модуля (и/или командная строка)
        Набор переменных окружения

    Список нитей процесса

  Состояния процесса

  Управление физической памятью

Управление реальной памятью
Bitmap
List

Стратегии выделения
    First fit
    Next  fit
    Best  fit
    Worst fit
    Quick fit

  Виртуальная память

Виртуальная память

    Сегментная
        Селектор.смещение

    Страничная
        Адресс страницы.смещение

  Отображение виртуальной памяти в физическую

Отображение виртуальной памяти в физическую

Адрессное пространство
    User
    Kernel

segment not present
page fault

  Подкачка

Swapping
    перемещение	moveable
    сброс кода	discardable
            swappable
    Зачистка использованных страниц при новом выделении

  Thrashing

Paged pool
Non-paged pool

Блокировка страниц (если на них буфер ввода-вывода)

Динамическое выделение стека
    (Win32 implementation)

  Сбой страницы

Page Fault

  Дисциплины вытеснения страниц

Алгоритмы вытеснения страниц

  FIFO

FIFO-

  additional reference bit
  second chance

  enhanced second chance

  LRU

NRU-    не использованная в последнее время
LRU-

  (Optimal)

Optimal

  Stack

Belady Anomaly

  Clock

Clock-

  Сравнение дисциплин

  Рабочий pool процесса

Рабочий pool процесса
    prepaging при старте процесса

  Жизненый цикл страницы

  Разделяемая память

бит обращения к странице (accessed)

Совмесное использование секций кода (если запущено несколько копий приложения)

Разделение между процессами

Разделение данных и кода

fork()
    копия адрессного пространства
    (оптимизация - copy-on-write)

vfork()
    управление возращается родителю только после вызова childом
    exec()

TLS (Thread Local Storage)

Memory Mapped Files


80.1.3.3. ПРОГРАММЫ

THIS SECTION IS UNDER CONSTRUCTION

Секция кода шариться между экземплярами программы

BSS секция указывает на нулевую страницу при записи идет копирование

  Выделение памяти

  fork()

Секция данных копируются ссылки страниц, но если потом идет обращение
то делают новую страницу (copy-on-write)

Побочный эффект fork() - обновление таблиц файлов

  dup()

  dup2()

  pipe()


80.1.3.4. ДИНАМИЧЕСКИЕ БИБЛИОТЕКИ

THIS SECTION IS UNDER CONSTRUCTION

THIS SECTION IS UNDER CONSTRUCTION

 Windows

HANDLE LoadLibrary(LPCSTR lpLibFileName);

void	FreeLibrary(HANDLE hLibHandle);

FARPROC GetProcAddress(HANDLE hModule, LPSTR lpProcName)

FARPROC MakeProcInstance(FARPROC lpProc, HANDLE hInstance)
    // создает точку входа ээкспортируемой процедуры

#define MAKEINTRESOURCE(i) ((LPSTR) ((DWORD)(WORD)(i))

    DllEntryPoint
    DLL_PROCESS_ATTACH
    DLL_PROCESS_DETACH
    DLL_THREAD_ATTACH
    DLL_THREAD_DETACH

    LoadLibrary
    FreeLibrary
    GetProcAddress
    LoadLibraryEx
    GetModuleHandle
    FreeLibraryAndExitThread
    DisableThreadLibraryCalls

Cross DLLs

Thunks

    LoadLibrary16
    GetProcAddress16
    FreeLibrary16

    LoadLibrary32W
    FreeLibrary32W
    GetProcAddress32W

    LoadLibrarty32


80.1.3.5. TLS (THREAD LOCAL STORAGE)

THIS SECTION IS UNDER CONSTRUCTION

TLS

 Windows

    DWORD	TlsAlloc(VOID)
    BOOL	TlsFree(DWORD dwTlsIdndex)
    BOOL	TlsSetValue(DWORD dwTlsIndex,
                LPVOID lpTlsValue)
    LPVOID	TlsGetValue(DWORD dwTlsIndex)

Пример кода инкрементации переменной:

int	x;

void main()
{
    x++;
}

; 7    : 	x++;

  00003	a1 00 00 00 00	 mov	 eax, DWORD PTR _x
  00008	83 c0 01	 add	 eax, 1
  0000b	a3 00 00 00 00	 mov	 DWORD PTR _x, eax

Пример кода инкрементации переменной находящейся в TLS

__declspec(thread) int	x;

void main()
{
    x++;
}

PUBLIC	_x
_TLS	SEGMENT
_x	DD	00H
_TLS	ENDS

EXTRN	__tls_index:DWORD
EXTRN	__tls_array:DWORD

; 7    : 	x++;

  00003	a1 00 00 00 00	 mov	 eax, DWORD PTR __tls_index
  00008	64 8b 0d 00 00
    00 00		 mov	 ecx, DWORD PTR fs:__tls_array
  0000f	8b 14 81	 mov	 edx, DWORD PTR [ecx+eax*4]
  00012	8b 82 00 00 00
    00		 mov	 eax, DWORD PTR _x[edx]
  00018	83 c0 01	 add	 eax, 1
  0001b	8b 0d 00 00 00
    00		 mov	 ecx, DWORD PTR __tls_index
  00021	64 8b 15 00 00
    00 00		 mov	 edx, DWORD PTR fs:__tls_array
  00028	8b 0c 8a	 mov	 ecx, DWORD PTR [edx+ecx*4]
  0002b	89 81 00 00 00
    00		 mov	 DWORD PTR _x[ecx], eax

Собственно стандартная библиотека тоже имеет thread-specific
кусок.
Например для Visual C++ он находится по метке _tiddata.
Собственно он описан в секции 91.5.2. ПОТОКИ


80.1.3.6. СТРУКТУРЫ НИТЕЙ/ПРОЦЕССОВ НА ПРИМЕРАХ

THIS SECTION IS UNDER CONSTRUCTION

  Windows Vista

typedef struct _KTHREAD
{
     DISPATCHER_HEADER Header;
     UINT64 CycleTime;
     ULONG HighCycleTime;
     UINT64 QuantumTarget;
     PVOID InitialStack;
     PVOID StackLimit;
     PVOID KernelStack;
     ULONG ThreadLock;
     union
     {
          KAPC_STATE ApcState;
          UCHAR ApcStateFill[23];
     };
     CHAR Priority;
     WORD NextProcessor;
     WORD DeferredProcessor;
     ULONG ApcQueueLock;
     ULONG ContextSwitches;
     UCHAR State;
     UCHAR NpxState;
     UCHAR WaitIrql;
     CHAR WaitMode;
     LONG WaitStatus;
     union
     {
          PKWAIT_BLOCK WaitBlockList;
          PKGATE GateObject;
     };
     union
     {
          ULONG KernelStackResident: 1;
          ULONG ReadyTransition: 1;
          ULONG ProcessReadyQueue: 1;
          ULONG WaitNext: 1;
          ULONG SystemAffinityActive: 1;
          ULONG Alertable: 1;
          ULONG GdiFlushActive: 1;
          ULONG Reserved: 25;
          LONG MiscFlags;
     };
     UCHAR WaitReason;
     UCHAR SwapBusy;
     UCHAR Alerted[2];
     union
     {
          LIST_ENTRY WaitListEntry;
          SINGLE_LIST_ENTRY SwapListEntry;
     };
     PKQUEUE Queue;
     ULONG WaitTime;
     union
     {
          struct
          {
               SHORT KernelApcDisable;
               SHORT SpecialApcDisable;
          };
          ULONG CombinedApcDisable;
     };
     PVOID Teb;
     union
     {
          KTIMER Timer;
          UCHAR TimerFill[40];
     };
     union
     {
          ULONG AutoAlignment: 1;
          ULONG DisableBoost: 1;
          ULONG EtwStackTraceApc1Inserted: 1;
          ULONG EtwStackTraceApc2Inserted: 1;
          ULONG CycleChargePending: 1;
          ULONG CalloutActive: 1;
          ULONG ApcQueueable: 1;
          ULONG EnableStackSwap: 1;
          ULONG GuiThread: 1;
          ULONG ReservedFlags: 23;
          LONG ThreadFlags;
     };
     union
     {
          KWAIT_BLOCK WaitBlock[4];
          struct
          {
               UCHAR WaitBlockFill0[23];
               UCHAR IdealProcessor;
          };
          struct
          {
               UCHAR WaitBlockFill1[47];
               CHAR PreviousMode;
          };
          struct
          {
               UCHAR WaitBlockFill2[71];
               UCHAR ResourceIndex;
          };
          UCHAR WaitBlockFill3[95];
     };
     UCHAR LargeStack;
     LIST_ENTRY QueueListEntry;
     PKTRAP_FRAME TrapFrame;
     PVOID FirstArgument;
     union
     {
          PVOID CallbackStack;
          ULONG CallbackDepth;
     };
     PVOID ServiceTable;
     UCHAR ApcStateIndex;
     CHAR BasePriority;
     CHAR PriorityDecrement;
     UCHAR Preempted;
     UCHAR AdjustReason;
     CHAR AdjustIncrement;
     UCHAR Spare01;
     CHAR Saturation;
     ULONG SystemCallNumber;
     ULONG Spare02;
     ULONG UserAffinity;
     PKPROCESS Process;
     ULONG Affinity;
     PKAPC_STATE ApcStatePointer[2];
     union
     {
          KAPC_STATE SavedApcState;
          UCHAR SavedApcStateFill[23];
     };
     CHAR FreezeCount;
     CHAR SuspendCount;
     UCHAR UserIdealProcessor;
     UCHAR Spare03;
     UCHAR Iopl;
     PVOID Win32Thread;
     PVOID StackBase;
     union
     {
          KAPC SuspendApc;
          struct
          {
               UCHAR SuspendApcFill0[1];
               CHAR Spare04;
          };
          struct
          {
               UCHAR SuspendApcFill1[3];
               UCHAR QuantumReset;
          };
          struct
          {
               UCHAR SuspendApcFill2[4];
               ULONG KernelTime;
          };
          struct
          {
               UCHAR SuspendApcFill3[36];
               PKPRCB WaitPrcb;
          };
          struct
          {
               UCHAR SuspendApcFill4[40];
               PVOID LegoData;
          };
          UCHAR SuspendApcFill5[47];
     };
     UCHAR PowerState;
     ULONG UserTime;
     union
     {
          KSEMAPHORE SuspendSemaphore;
          UCHAR SuspendSemaphorefill[20];
     };
     ULONG SListFaultCount;
     LIST_ENTRY ThreadListEntry;
     LIST_ENTRY MutantListHead;
     PVOID SListFaultAddress;
     PVOID MdlForLockedTeb;
} KTHREAD, *PKTHREAD;

typedef struct _DISPATCHER_HEADER
{
     union
     {
          struct
          {
               UCHAR Type;
               union
               {
                    UCHAR Abandoned;
                    UCHAR Absolute;
                    UCHAR NpxIrql;
                    UCHAR Signalling;
               };
               union
               {
                    UCHAR Size;
                    UCHAR Hand;
               };
               union
               {
                    UCHAR Inserted;
                    UCHAR DebugActive;
                    UCHAR DpcActive;
               };
          };
          LONG Lock;
     };
     LONG SignalState;
     LIST_ENTRY WaitListHead;
} DISPATCHER_HEADER, *PDISPATCHER_HEADER;

typedef struct _KAPC_STATE
{
     LIST_ENTRY ApcListHead[2];
     PKPROCESS Process;
     UCHAR KernelApcInProgress;
     UCHAR KernelApcPending;
     UCHAR UserApcPending;
} KAPC_STATE, *PKAPC_STATE;

typedef struct _KWAIT_BLOCK
{
     LIST_ENTRY WaitListEntry;
     PKTHREAD Thread;
     PVOID Object;
     PKWAIT_BLOCK NextWaitBlock;
     WORD WaitKey;
     UCHAR WaitType;
     UCHAR SpareByte;
} KWAIT_BLOCK, *PKWAIT_BLOCK;

typedef struct _KGATE
{
     DISPATCHER_HEADER Header;
} KGATE, *PKGATE;

typedef struct _KQUEUE
{
     DISPATCHER_HEADER Header;
     LIST_ENTRY EntryListHead;
     ULONG CurrentCount;
     ULONG MaximumCount;
     LIST_ENTRY ThreadListHead;
} KQUEUE, *PKQUEUE;

typedef struct _KTIMER
{
     DISPATCHER_HEADER Header;
     ULARGE_INTEGER DueTime;
     LIST_ENTRY TimerListEntry;
     PKDPC Dpc;
     LONG Period;
} KTIMER, *PKTIMER;

typedef struct _TEB
{
     NT_TIB NtTib;
     PVOID EnvironmentPointer;
     CLIENT_ID ClientId;
     PVOID ActiveRpcHandle;
     PVOID ThreadLocalStoragePointer;
     PPEB ProcessEnvironmentBlock;
     ULONG LastErrorValue;
     ULONG CountOfOwnedCriticalSections;
     PVOID CsrClientThread;
     PVOID Win32ThreadInfo;
     ULONG User32Reserved[26];
     ULONG UserReserved[5];
     PVOID WOW32Reserved;
     ULONG CurrentLocale;
     ULONG FpSoftwareStatusRegister;
     VOID * SystemReserved1[54];
     LONG ExceptionCode;
     PACTIVATION_CONTEXT_STACK ActivationContextStackPointer;
     UCHAR SpareBytes1[36];
     ULONG TxFsContext;
     GDI_TEB_BATCH GdiTebBatch;
     CLIENT_ID RealClientId;
     PVOID GdiCachedProcessHandle;
     ULONG GdiClientPID;
     ULONG GdiClientTID;
     PVOID GdiThreadLocalInfo;
     ULONG Win32ClientInfo[62];
     VOID * glDispatchTable[233];
     ULONG glReserved1[29];
     PVOID glReserved2;
     PVOID glSectionInfo;
     PVOID glSection;
     PVOID glTable;
     PVOID glCurrentRC;
     PVOID glContext;
     ULONG LastStatusValue;
     UNICODE_STRING StaticUnicodeString;
     WCHAR StaticUnicodeBuffer[261];
     PVOID DeallocationStack;
     VOID * TlsSlots[64];
     LIST_ENTRY TlsLinks;
     PVOID Vdm;
     PVOID ReservedForNtRpc;
     VOID * DbgSsReserved[2];
     ULONG HardErrorMode;
     VOID * Instrumentation[9];
     GUID ActivityId;
     PVOID SubProcessTag;
     PVOID EtwLocalData;
     PVOID EtwTraceData;
     PVOID WinSockData;
     ULONG GdiBatchCount;
     UCHAR SpareBool0;
     UCHAR SpareBool1;
     UCHAR SpareBool2;
     UCHAR IdealProcessor;
     ULONG GuaranteedStackBytes;
     PVOID ReservedForPerf;
     PVOID ReservedForOle;
     ULONG WaitingOnLoaderLock;
     PVOID SavedPriorityState;
     ULONG SoftPatchPtr1;
     PVOID ThreadPoolData;
     VOID * * TlsExpansionSlots;
     ULONG ImpersonationLocale;
     ULONG IsImpersonating;
     PVOID NlsCache;
     PVOID pShimData;
     ULONG HeapVirtualAffinity;
     PVOID CurrentTransactionHandle;
     PTEB_ACTIVE_FRAME ActiveFrame;
     PVOID FlsData;
     PVOID PreferredLanguages;
     PVOID UserPrefLanguages;
     PVOID MergedPrefLanguages;
     ULONG MuiImpersonation;
     WORD CrossTebFlags;
     ULONG SpareCrossTebBits: 16;
     WORD SameTebFlags;
     ULONG DbgSafeThunkCall: 1;
     ULONG DbgInDebugPrint: 1;
     ULONG DbgHasFiberData: 1;
     ULONG DbgSkipThreadAttach: 1;
     ULONG DbgWerInShipAssertCode: 1;
     ULONG DbgRanProcessInit: 1;
     ULONG DbgClonedThread: 1;
     ULONG DbgSuppressDebugMsg: 1;
     ULONG SpareSameTebBits: 8;
     PVOID TxnScopeEnterCallback;
     PVOID TxnScopeExitCallback;
     PVOID TxnScopeContext;
     ULONG LockCount;
     ULONG ProcessRundown;
     UINT64 LastSwitchTime;
     UINT64 TotalSwitchOutTime;
     LARGE_INTEGER WaitReasonBitMap;
} TEB, *PTEB;

typedef struct _NT_TIB
{
     PEXCEPTION_REGISTRATION_RECORD ExceptionList;
     PVOID StackBase;
     PVOID StackLimit;
     PVOID SubSystemTib;
     union
     {
          PVOID FiberData;
          ULONG Version;
     };
     PVOID ArbitraryUserPointer;
     PNT_TIB Self;
} NT_TIB, *PNT_TIB;

typedef struct _KPROCESS
{
     DISPATCHER_HEADER Header;
     LIST_ENTRY ProfileListHead;
     ULONG DirectoryTableBase;
     ULONG Unused0;
     KGDTENTRY LdtDescriptor;
     KIDTENTRY Int21Descriptor;
     WORD IopmOffset;
     UCHAR Iopl;
     UCHAR Unused;
     ULONG ActiveProcessors;
     ULONG KernelTime;
     ULONG UserTime;
     LIST_ENTRY ReadyListHead;
     SINGLE_LIST_ENTRY SwapListEntry;
     PVOID VdmTrapcHandler;
     LIST_ENTRY ThreadListHead;
     ULONG ProcessLock;
     ULONG Affinity;
     union
     {
          ULONG AutoAlignment: 1;
          ULONG DisableBoost: 1;
          ULONG DisableQuantum: 1;
          ULONG ReservedFlags: 29;
          LONG ProcessFlags;
     };
     CHAR BasePriority;
     CHAR QuantumReset;
     UCHAR State;
     UCHAR ThreadSeed;
     UCHAR PowerState;
     UCHAR IdealNode;
     UCHAR Visited;
     union
     {
          KEXECUTE_OPTIONS Flags;
          UCHAR ExecuteOptions;
     };
     ULONG StackCount;
     LIST_ENTRY ProcessListEntry;
     UINT64 CycleTime;
} KPROCESS, *PKPROCESS;

typedef struct _PEB
{
     UCHAR InheritedAddressSpace;
     UCHAR ReadImageFileExecOptions;
     UCHAR BeingDebugged;
     UCHAR BitField;
     ULONG ImageUsesLargePages: 1;
     ULONG IsProtectedProcess: 1;
     ULONG IsLegacyProcess: 1;
     ULONG IsImageDynamicallyRelocated: 1;
     ULONG SpareBits: 4;
     PVOID Mutant;
     PVOID ImageBaseAddress;
     PPEB_LDR_DATA Ldr;
     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
     PVOID SubSystemData;
     PVOID ProcessHeap;
     PRTL_CRITICAL_SECTION FastPebLock;
     PVOID AtlThunkSListPtr;
     PVOID IFEOKey;
     ULONG CrossProcessFlags;
     ULONG ProcessInJob: 1;
     ULONG ProcessInitializing: 1;
     ULONG ReservedBits0: 30;
     union
     {
          PVOID KernelCallbackTable;
          PVOID UserSharedInfoPtr;
     };
     ULONG SystemReserved[1];
     ULONG SpareUlong;
     PPEB_FREE_BLOCK FreeList;
     ULONG TlsExpansionCounter;
     PVOID TlsBitmap;
     ULONG TlsBitmapBits[2];
     PVOID ReadOnlySharedMemoryBase;
     PVOID HotpatchInformation;
     VOID * * ReadOnlyStaticServerData;
     PVOID AnsiCodePageData;
     PVOID OemCodePageData;
     PVOID UnicodeCaseTableData;
     ULONG NumberOfProcessors;
     ULONG NtGlobalFlag;
     LARGE_INTEGER CriticalSectionTimeout;
     ULONG HeapSegmentReserve;
     ULONG HeapSegmentCommit;
     ULONG HeapDeCommitTotalFreeThreshold;
     ULONG HeapDeCommitFreeBlockThreshold;
     ULONG NumberOfHeaps;
     ULONG MaximumNumberOfHeaps;
     VOID * * ProcessHeaps;
     PVOID GdiSharedHandleTable;
     PVOID ProcessStarterHelper;
     ULONG GdiDCAttributeList;
     PRTL_CRITICAL_SECTION LoaderLock;
     ULONG OSMajorVersion;
     ULONG OSMinorVersion;
     WORD OSBuildNumber;
     WORD OSCSDVersion;
     ULONG OSPlatformId;
     ULONG ImageSubsystem;
     ULONG ImageSubsystemMajorVersion;
     ULONG ImageSubsystemMinorVersion;
     ULONG ImageProcessAffinityMask;
     ULONG GdiHandleBuffer[34];
     PVOID PostProcessInitRoutine;
     PVOID TlsExpansionBitmap;
     ULONG TlsExpansionBitmapBits[32];
     ULONG SessionId;
     ULARGE_INTEGER AppCompatFlags;
     ULARGE_INTEGER AppCompatFlagsUser;
     PVOID pShimData;
     PVOID AppCompatInfo;
     UNICODE_STRING CSDVersion;
     _ACTIVATION_CONTEXT_DATA * ActivationContextData;
     _ASSEMBLY_STORAGE_MAP * ProcessAssemblyStorageMap;
     _ACTIVATION_CONTEXT_DATA * SystemDefaultActivationContextData;
     _ASSEMBLY_STORAGE_MAP * SystemAssemblyStorageMap;
     ULONG MinimumStackCommit;
     _FLS_CALLBACK_INFO * FlsCallback;
     LIST_ENTRY FlsListHead;
     PVOID FlsBitmap;
     ULONG FlsBitmapBits[4];
     ULONG FlsHighIndex;
     PVOID WerRegistrationData;
     PVOID WerShipAssertPtr;
} PEB, *PPEB;

typedef struct _PEB_LDR_DATA
{
     ULONG Length;
     UCHAR Initialized;
     PVOID SsHandle;
     LIST_ENTRY InLoadOrderModuleList;
     LIST_ENTRY InMemoryOrderModuleList;
     LIST_ENTRY InInitializationOrderModuleList;
     PVOID EntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;


80.1.3.7. СТРУКТУРЫ СИНХРОНИЗАЦИИ

THIS SECTION IS UNDER CONSTRUCTION


80.1.3.8. IPC

THIS SECTION IS UNDER CONSTRUCTION

IPC (Interprocess communications)

  Критические секции

Critical Sections

  Семафоры

Semaphore
Mutex
Spin-lock

  Deadlock

  Мониторы

Monitor

  Барьеры

Barriers

  Сообщения

Message-parsing
    Mailbox
    Port
    Pipe

  Сигналы

Signals

  RPC

RPC (Remote procedure call)

  Разделяемая память

Shared memory


80.1.3.9. КЛАСТЕРЫ

THIS SECTION IS UNDER CONSTRUCTION

TODO:	Cluster
    Quorum
    Failover
    Network Load Balancing

  Распределенные и кластерные файловые системы

  Storage Tiering


80.1.3.10.1. ФАЙЛОВЫЕ СЕРВИСЫ ОПЕРАЦИОННЫХ СИСТЕМ

THIS SECTION IS UNDER CONSTRUCTION

TODO: Типичные интерфейсы FSD
      Типичные интерфейсы Storage Devices
      Что происходит внутри файловой подсистемы
      Какие сервисы предоставляются


80.1.3.10.2. СЕТЕВЫЕ СРЕДСТВА ОПЕРАЦИОННЫХ СИСТЕМ

THIS SECTION IS UNDER CONSTRUCTION

TODO: Типичные интерфейсы сетевых устройств
      Типичные интерфейсы протоколов
      Что происходит внутри стека
      Какие сервисы предоставляются


80.1.4. ИНСТРУМЕНТЫ РАЗРАБОТКИ

THIS SECTION IS UNDER CONSTRUCTION


80.1.4.1. ОБЩЕЕ УСТРОЙСТВО КОМПИЛЯТОРОВ

THIS SECTION IS UNDER CONSTRUCTION


80.1.4.1.1. ОПТИМИЗАЦИИ ВНУТРИ КОМПИЛЯТОРОВ

THIS SECTION IS UNDER CONSTRUCTION

Оптимизация

TODO: Детальные примеры на все случаи

    Константные выражения
    Алгебраическое упрощение и переассоциация
        -(-x)   x*1  x+0  x&true x|true x << 0
        x +a -a
    Value numbering
        i = x * 2 + 1;
        j = x * 2 + 1;
    Быстрое вычисление AND/OR
    SP-based frames
    Оптимизация subexpressions
    Замена деления на константу умножением
    Замена умножений на константу сдвигами

    Раскраска регистров нетрезвыми красочками

    Отказ от ветвлений

    Оптимизация циклов
        Разворот цикла
        Регистрация переменной цикла

Векторизация

    Конкурентизация циклов
        разделение на части которые отдаются разным процессорам
    Разделение операций на высшем уровне

             * (CPU2)
                / \
          (CPU1) +   C
                      / \
                     A   B

    Переименование переменных (так же как регистров в CPU)
    Расщепление зависимостей по данным
    Растягивания скаляров (в векторные регистры)
    Перестановка вложенных циклов
    Слияние циклов
    Разрыв итераций (делит циклы на циклы по длинне вектора)
    Коллапс циклов
    Условные присваивания (если аппаратно поддерживаются)
    Выявление и упрощение индуктивных ьэлементов
    Распознование охватывающих элементов
    Расщепление вершин (копирование данных)
    Чистка циклов (вынос инвариантного кода)
    Расширение циклов (смежные циклы с зависимостями по данным)


80.1.4.1.2. ТИПОВЫЕ ВНУТРЕННИЕ СТРУКТУРЫ КОМПИЛЯТОРОВ

THIS SECTION IS UNDER CONSTRUCTION

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


80.1.4.2. АССЕМБЛЕРЫ

THIS SECTION IS UNDER CONSTRUCTION

Ассемблер - программа переводящая мнемонические коды для конкретной машины в
машинное представление.

Команда может иметь разную длинну - зависит от операнда
Если операнд метка, то возможна короткая форма (зависит от CPU)
Поэтому практически всегда 2 прохода.

Например:

    jmp	L1	; не знаем где находиться L1
    ...		; возможны формы:
            ; 	jmp short L1
            ; 	jmp near  L1
            ; они имеют разный размер
   L1:

  Объектные файлы

Информация которая кладется в объектные файлы.

    Описание секций
        code/data/bss
        аттрибуты: (RO/RW, Executable, Loadable)

Описание символов:
    Имя символа
    Номер секции
    Смещение в секции
    Тип символа
        Локальный (виден только в этом модуле)
        Глобальный
            public  (определен в этом модуле, виден наружу)
            extern  (определен снаружи(

Описание ссылки на символ:
    Назначение ссылки
        Символ
    Место ссылки
        Номер секции
        Смещение в секции
    Тип фиксапа
        Зависит от платформы очень сильно
            Относительный
            Абсолютный
            IP-относительный
            итд.

    call	_printf
        Тип фиксапа: Relative 32
        Код:         E8  00  00  00  00
                +---------------+
                 Fixup area
        Ссылка:	     _printf

    mov eax, [label1 + 4]
        Тип фиксапа:  Absolute 32
                 A1  04  00  00  00
                                 ==============
                 Fixup area
        Ссылка:	     label4

    add rax, [label1 + 4]
                         48 01 05 04 00 00 00
                                      ===========    ^
                 ^		Fixup area   |
                 |		             IP of next instruction
                 IP of current instruction
         Тип фиксапа: IP Related (за 4 байта до next IP)

TODO: x64 IP-based fixups

  Как работает ассемблер

Основной ход
    Прочитать команду
    В зависимости от команды
    директива
        END
            закончить
        SECTION
            начать новую секцию с указанными свойствами
        ORG
            поставить новый текущий адресс в текущей секции
        DB/DW/DD
            прочитать данные
            записать данные в текущую секцию начиная с тек адресса
        PUBLIC/EXTERN
            поставить информацию о метке

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


80.1.4.3. ЛИНКЕРЫ

THIS SECTION IS UNDER CONSTRUCTION

    Есть начальная метка

    Берем неразрешенную метку из стека
    Смотрим есть ли она у нас в pool
        Если есть то разрешаем
    Смотрим есть ли она у нас в исходных файлах
      Если есть
           Грузим модуль
        Добовляем все его public в список разрешенных меток
            Если уже такие есть - то duplicate symbol error
        Добовляем все его extern в стек неразрешенных меток
      Если нет
        Символ не найден

    И так пока метки не закончаться
    Как закончаться то линковка закончена

    Сохранить pool в выходном файле в нужном формате.

THIS SECTION IS UNDER CONSTRUCTION

Библиотекарь

    Объединяет объектные файлы в архив
    Строит доп таблицы оглавления для архива, чтобы линкер
    мог быстрее работать.


80.1.4.4. MAKE

THIS SECTION IS UNDER CONSTRUCTION

    Зависимости компонентов
        Явные зависимости (explicit)
        Неявные зависимости (implicit) - правила
        Зависимости по include файлам
            Отслеживать наиболее тяжело так как надо
            знать include paths.
    Паралельный Make

Проход 1:
    Строим дерево зависимости задач

Проход 2:
    Начинаем обходить дерево и выполнять задачи

TODO: Примеры


80.1.4.5. КОНТРОЛЬ ВЕРСИЙ

THIS SECTION IS UNDER CONSTRUCTION


80.2.1. БАЗЫ ДАННЫХ

THIS SECTION IS UNDER CONSTRUCTION

    Базы данных
       /      |     \
Простые Реляционные  Объектные

  Реляционная алгебра

Основная идея реляционной алгебры:
    т.к. отношения являются множествами то средства манипулирования
    ими тоже являются множествами.

Def
===
Множество - любая определенная совокупность объектов.
Объекты из которых составлено множество называются его элементами.
Элементы множества по определению различны и отличимы друг от друга.

Def
===
Мультимножество - одинаковые элементы могут входить несколько раз.

Def
===
Прямое (Декартово) произведение двух множеств A x B- множество содержащие все возможные
пары (a,b), где a - принадлежит множеству A, а B - принадлежит множеству B.

Def
===
Пусть A и B - два множества. Бинарным отношением из множества A в множество B
называется тройка [A,B,R], где R - подмножество декартово произведения A x B.
(Среди элементов множеств A и B могут быть такие, какие не входят ни в одну из
пар определяющих отношение R).

(Собственно отношение R из множества А во множество B - это в общем виде не
тоже самое что отношение R из множества B во множества A.

Def
===
Пусть R - отношение из множества A во множество A.
Тогда R:

    рефлексивно, если для любого элемента а множества A
             в отношение входит aRa

    антирефлексивно, если для любого элементв множества A
             в отношение не входит aRa

    нерефлексивно, если оно не рефлексивно, не антирефлексивно

    симметрично, если для любых элементов a и b множества A
                 если в отношение входит aRb, то входит и bRa

    антисимметрично, если для любых элементов a и b множества A
             если в отношение входят aRb и bRa, то a = b

    ассиметрично, если для любых элементов a и b множества A
              если в отношение входит aRb, то bRa не входит

    несимметрично, если отношение ни симметрично ни антисиммитрично

    транзитивно, если для любых элементов a,b и с множества A
             если в отношение входят aRb и bRc, то aRc тоже входит в отношение

    интранзитивно, если для любых элементов a,b и с множества A
             если в отношение входят aRb и bRc, то aRc не входит в отношение

    нетранзитивно, если отношение ни транзитивно не интранзитивно

    линейным, если для любых элементов a и b множества A
             либо a = b, либо aRb входит в отношение, либо bRa входит в отношение

Примеры:

Рефлексивное отношение:
    >=		a >= a  всегда входит в отношение >=

Нерефлексивное отношение:
    >		a > a   всегда невходит в отношение >

Симметричное отношение:
    =		из a = b, следует b = a

Антисимметричное:
    >=		если a >= b, и b >= a, то a = b

Транзитивное:
    >		если a > b, и b > c,  то a > c

Def
===
Ассимметричное транзитивное отношение - называется отношением порядка.

Если отношение порядка рефлексивно, то оно называется отношением нестрогово порядка
Если отношение порядка антирейлексивно, то оно называется отношением строгово порядка
Если отношения порядка линейно, то оно называется отношением линейного порядка
Если отношение порядка не линейно, то оно называется отношением частичного порядка

Def
====
Рефлексивное Симметричное Транзитивное отношение - называется отношением
экивалентности.

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

Def
===
Если из  b = f(a1) и b = f(a2) следует что a1 = a2, то такая функция называется иньекцией.

Def
===
Если для любого b принадлежащему B cуществует a принадлежащий A, такой что
b = f(a), то такая функция называется сюрьекцией

Def
===
Если функция одновременно является и иньекцией и сюрьекцией то такая функция называется
биекцией.

Домен - множество фтомарных значений одного и того же типа

Отношение - множество, по определению не имеет совпадающих элементов
Заголовок отношения содержит множество аттрибутов
Тело отношения содержит множество меняющихся во времени кортежей

Кортеж - множество пар (аттрибут-значение)

Степень отношения - число его аттрибутов

Мощность отношения - число кортежей

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

Операции:

   Теоретико-множественные
    Объединение
    Пересечение
    Разность
    Прямое произведение отношений
   Специальные реляционные
    Ограничение отношения
    Проекция отношения
    Соотношение отношений
    Деление отношений
   Примитивы
    Добавление
    Удаление
    Изменение

    Обмен позициями
    Исключение позиции
    Удвоение позиции
    Расширение отношения
        добавляется новая позиция

Отношение (binary relation) R между элементами множеств A и B - подмножество
декартово произведения AxB

Пишут что если  (a,b) принадлежит R, то aRb
    например a>b
    или	 a<=b
    итд.

  Объединение

    все X, которые принадлежат хотя бы одному A или B
    UNION

  Пересечение

    все X, которые принадлежат одновременно A и B
    INTERSEC

    A INTERSEC B = A MINUS (A MINUS B)

  Разность

    все Х входящие в А, но не входящие в B
    MINUS

  Прямое произведение

Декартого произведение
    в результате имеем {x,y} для каждого х в А и y в B.
    TIMES

Пример
    A	{a,b}
    B	{a,b,c}

    AxB  	{(a,a),(a,b),(a,c),(b,a),(b,b),(b,c)}

  Ограничение отношения

Выборка

    все Х из А для которых выполняется условие ограничения
    A WHERE c

WHERE c1 AND c2      		(A WHERE c1) INTERSECT (A WHERE c2)
WHERE c1 OR  c2			(A WHERE c1) UNION (A WHERE c2)
WHERE NOT c1			A MINUS (A WHERE c1)

  Проекция

    Отношение с заголовком (X,Y..Z) и телом вида (x,y, ...z)
таких для которые в отношении А найдуться кортежи со значением X = x, Y =y,
Z = z

    A[X,Y,...Z]

  Соединение

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

    (A TIMES B) WHERE c

Соединение R c T по столбцам i и j -  R[i (-) j] T,
то есть строки в декартовом произведении R X T, в котором значение из i
столбца R, находиться в отношении (-) со значением j-го столбца T.

Эквисоединение - когда (-) - это отношение равенства

Естественное соединение - эквисоединение в котором исключен столбец j.

Композиция - эквисоединение, где исключены столбцы по которым производилось
соединение.

Тетасоединение - соединение где отношение (-) - отлично от отношения равенства.

Sort-Merge Join
предварительная сортировка таблиц по атрибутам на которых будет делаться join.

Join Selection Factor
определяет насколько разряжены атрибуты по которым будет делаться join

Nested loop join

Hash Join

  Деление

    A DIVIDEBY B
    A DIVIDEBY B = A[X] MINUS ((A[X] TIMES B) MINUS A)[X]

Реляционное деление - имеет два операнда - бинарный {X,Y} и унарный {Y}.
Результатирующее отношение состоит из одноатрибутных кортежей включающих значение
первого атрибута 1го операнда таких что множество значений 2го аттрибута (при фиксированном
значение 1го аттрибута) совпадает с множеством значений второго операнда.

       M1          M2         M3 = M1 divideby M2
    A  B  C        A          B   C
       --------	      ---	 -------
        a  b  d        a	  b   d
        a  c  d        e          c   d
    e  b  d
        e  c  d

       M1           M2        M3 = M1 divideby M2
    A  B  C  D     A  B       C  D
       ------------   ------	 -------
    a  b  c  d     a  b       c  d
        a  b  b  d     e  d       b  d
    a  b  e  f                e  f
    e  d  c  d
    e  d  b  d
    e  d  e  f

       M1           M2        M3 = M1 divideby M2
    A  B  C  D     A  B       C  D
       ------------   ------	 -------
    a  b  c  d     c  d       a  b
    a  b  e  f     e  f       e  d
    b  c  c  d
    e  d  c  d
    e  d  e  f
    c  b  e  f

Мощность множества - число элементов в нем
    |0| = 0
    | A or B | = |A| + |B| - |A and B|
    | A X  B | = |A| * |B|

Реляционные базы данных - данные хранятся в таблицах

    primary key
    foreign key

Типы бинарных связей
    1:1
    1:N
    N:M

  Нормальные формы

Назначение нормальных форм - приведение структуры базы данных к виду
обеспечивающиму минимальную избыточность

Классы отношений
    DKNF
    5NF
    4NF
    BCNF
    3NF
    2NF
    1NF

1NF

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

2NF

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

3NF

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

NFBC

Нормальная форма Бойса-Кодда
3NF + Все зависимые от первичного ключа атрибуты должны быть потенциальными ключами отношения

4NF

NFBC + не содержит нетривиальных многозначных зависимостей

Def
===
Пусть существует отношение R, а так же три его подмножества A,B и С
В многозначно зависит от A, тогда и только тогда когда множество значений атрибута B
соответсвующее паре значений [a,c], где a принадлежит A, а c - принадлежит C,
зависит только от a, и не зависит от с.

5NF

4NF + любая многозначная зависимость является тривиальной

DKNF

(Domain-Key Normal Form)  6NF

  Транзакции

Свойства транзакции:

Атомарность - либо выполняется, либо нет

Непротиворечивость - оставляет данные в непротиворечивом состоянии
(например для таблиц - не должно получаться строк дубликатов)

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

Долговечность - изменения сделаннные успешной транзакцией остаются даже если
сбой питания.

Состояния транзакции

Типы транзакций

    RC - Recoverable - каждая транзакция коммититься только после того,
         как все транзакции из которых она читает закоммичены.
    ACR - Avoid Cascading Rollback - Каждая транзакция может читать только
          закоммиченные данные.
    ST  - Strict - каждая транзакция может читать и писать закоммиченные данные.

Проблемы доступа

Неповторяющиеся чтение (non-repeatable read)

Грязное чтение (dirty read)
Temporary update

    ---------------------------------------
        T1		T2
    ---------------------------------------
        READ(X)
        ...
        WRITE(X)
        ...
        ...		READ(X)
        ...		...
        ...		WRITE(X)
        ...
        READ(Y)
    ---------------------------------------
T1 fails and abort.

Потерянное обновление (lost update)

    ---------------------------------------
        T1		T2
    ---------------------------------------
        READ(X)
        ...		READ(X)
        ...		...
        ...		...
        WRITE(X)        ...
        READ(Y)		...
        ...		...
        ...             WRITE(X)
        WRITE(Y)
    ---------------------------------------

Фантомная вставка (phantom insert)

THIS SECTION IS UNDER CONSTRUCTION

Уровни изоляции транзакций

0 - Неподтверждённое чтение (Read Uncommited, Dirty Read, грязное чтение)
чтение незафиксированных изменений своей транзакции и конкурирующих транзакций,
возможны нечистые, неповторяемые чтения и фантомы

1 - Подтверждённое чтение (Read Commited) - чтение всех изменений своей транзакции
и зафиксированных изменений конкурирующих транзакций, нечистые чтения невозможны,
возможны неповторяемые чтения и фантомы

2 - Повторяемое чтение (Repeatable Read ,Snapshot) - чтение всех изменений своей транзакции,
любые изменения, внесённые конкурирующими транзакциями после начала своей недоступны,
нечистые и неповторяемые чтения невозможны, возможны фантомы

3 - Упорядоченный - (Serializable, сериализуемый) - упорядоченные (cериализуемые) транзакции.
Идентичен ситуации при которой транзакции выполняются строго последовательно одна после другой.
То есть транзакции, результат действия которых не зависит от порядка выполнения шагов
транзакции (запрещено чтение всех данных изменённых с начала транзакции, в том числе и своей
транзакцией). Фантомы невозможны.

Реализация транзакций
    Блокировка доступа
    Журнализация изменений (Write ahead Logging)  (in-place update)
    Shadow Paging  (copy-on-write)
        измененная версия страницы записывается в другое место

Two Phase Locking
    Транзакция следует двухфазному протоколу если все locks производяться до
первого unlock. И в shrinking phase не происходит новых locks.

Борьба с DeadLocks
    Wait-Die схема
        Ресурс захвачен Tj, нужен Ti
        Если timestamp(Ti) < timestamp(Tj)
            Ti ждет
        иначе
            Abort Ti, restart later с тем же timestamp
    Wound-Wait схема
        Ресурс захвачен Tj, нужен Ti
        Если timestamp(Ti) < timestamp(Tj)
            Abort Tj, restart later с тем же timestamp
        иначе
            Ti ждет

Distributed Transaction Coordinator

    Phase 0:
        Координатор инициирует протокол
        Присылает действия для участников
    Phase 1:
        Координатор спрашивает всех участников - могут ли они commit
        Участники отвечают - да или нет
    Phase 2:
        Если все ответили да - координатор посылает Commit участникам
            иначе присылает Abort
        Участники присылают - Has Commited/Have Aborted

Блокировки

Блокировка базы:

Блокировка таблицы:

Блокировка страницы:

Блокировка строки:

Shadow-paging

WAL (Write-Ahead Logging)

Журналирование изменений (ARIES)

    LSN (Log Sequence Number)
    Type	- compensation [откат части транзакции], update, commit
    TransID - transaction identifier
    PrevLSN
    PageID  - идентификатор страницы затронутой операцией
    UndoNxtLSN - номер следущей записи журнала, которую надо будет обработать при откате

Фазы обработки:
    Analysis
    Redo
    Undo

  Представление

Представление (View) - виртуальная таблица, результат запроса из базы данных.
Изменение базы приводит к изменению представлений.

  Индекс

Индекс - объект базы данных, создаваемый с целью повышения производительности запросов.

кластерный индекс - таблица храниться в оптимизированном порядке
Некластерный индекс - внешний

  Триггеры

Тригер - хранимая процедура особого типа, которая вызывается не непосредственно, а при
наступлении определенного события - INSERT или DELETE строки, UPDATE в столбце. итд
Триггеры бывают - BEFORE и AFTER.


80.3.1. КАК РАБОТАЕТ BROWSER?

THIS SECTION IS UNDER CONSTRUCTION

1) Получение данных по HTTP протоколу или чтением из файла

<html>
<head><title>Example</title></head>
<body>
<center><img src="pix.gif"></center>
<hr>
Example text long line <p>
<a href="link.htm"> Link Text </a>
</body>
</html>

2) Разбор в дерево

        HTML
         |
    +--------+------+
    |               |
    HEAD            BODY
    |               |
    TITLE           |
               CENTER --- HR --- (TEXT)  --- A
            |                            |
            IMG                         (TEXT)

3) Формирование координат для вывода
   Для картинки пока используется стандартная заглушка
   Если размеры заданы в таге IMG - то они
   Если нет - то стандартная картинка

4) Чтение вспомогательных элементов страницы
   (в частности картинки)
   Получение размеров картинки
   Маштабирование на указанный размер

5) Отображение
6) Смена размера
7) hyperlink - есть ли в дереве вышележащий тэг Anchor


80.3.2. КАК РАБОТАЕТ ТЕКСТОВЫЙ РЕДАКТОР?

THIS SECTION IS UNDER CONSTRUCTION

1) Структура текста
   Как правило списки строк

2) Отображение как line, column

3) Ввод символа

4) Удаление символа

5) Вставка новой строки

6) Навигация

7) Подсветка текста
    выделение ключевых слов
    выделение комментариев
    выделение скобок

8) Автоматическая генерация текста


80.3.3. КАК РАБОТАЕТ ТЕКСТОВЫЙ ПРОЦЕССОР?

THIS SECTION IS UNDER CONSTRUCTION


80.3.4. КАК РАБОТАЕТ ГРАФИЧЕСКИЙ РЕДАКТОР?

THIS SECTION IS UNDER CONSTRUCTION

Описать все основные команды графического редактора


80.3.5. КАК РАБОТАЕТ СИСТЕМЫ ВЕРСТКИ

Редактор векторной графики

THIS SECTION IS UNDER CONSTRUCTION


80.3.6. КАК РАБОТАЮТ ЭЛЕКТРОННЫЕ ТАБЛИЦЫ

THIS SECTION IS UNDER CONSTRUCTION


80.3.7. КАК РАБОТАЕТ OCR?

THIS SECTION IS UNDER CONSTRUCTION


81. ОСНОВНЫЕ ПОДСИСТЕМЫ

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

Это включает в себя:
    - Время
    - Память
    - Задачи
    - Управление процессами
    - Управление нитями
    - Файлы и Файловые системы (Storage)
    - Сетевая подсистема (Network)
    - Audio подсистема
    - Графическая подсистема
        UI


81.1. ПОДСИСТЕМА ВРЕМЕНИ

THIS SECTION IS UNDER CONSTRUCTION

  Типы времени

Времена:

    Реальное
        календарное -  12-Apr-2009, 23:13:56, Moscow Time Zone
            локальное (для конкретной timezone)
            UTC (Universal Time coordinated)

    Время выполнения процесса/нити
        Как правило с этим временем связаны процессорные квоты для
        процесса/ниты.

    Монотонное системное время
        Как правило отсчитывается от момента запуска системы
        Синхронизационные события завязаны именно на него
        Оно никогда не уменьшается
        Коррекции времени как правило убыстряют или замедляют скорость
        изменения монотонного системного времени на некоторое время.

Для разных задач требуются разные типы времен.

         Время
           /      \
 Абсолютное      Интервальное

  Реальное время

Есть различные способы измерения времени.

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

Но с месяцами и годами все уже обстоит по другому.
    Григорианский календарь (от рождества Христова)
    Лунная Хиджра (арабский календарь)
    Восточные календари (масса вариантов).
    и еще куча других

Как правило в компьютерном мире мы сталкиваемся с Григорианский календарем.

  Календарь от Рождества Христова

1 день = 24 часа  = 1440 минут = 86400 секунд
1 час  = 60 минут = 3600 секунд
1 минута = 60 секунд

1 сек = 10^9    наносек
1 сек = 1000000 микросек
1 сек = 1000 миллисек

Месяц. Количество дней в месяце зависит от его номера.
Для февраля возможен дополнительный день в високосные года.

Thirty days have September,
April, June and November,
And one day more,
One year in four.

Месяц	     кол-во дней
January		31
February	28/29
March		31
April		30
May		31
June		30
July		31
August		31
September	30
October		31
November	30
December	31

Таким образов в году получается 365/366 дней

Реально продолжительность года порядка 365.2422 дня

Не каждый год является високосным:
    Не кратный 4 - простой
    кратный 4    - високосный
        Исключение   - xx00 - если последние две цифры номера года нули - простой
        Исключение   - xx00 - если последние две цифры номера года нули, и  если часть номера
                              года предшествующая двум последним цифрам делиться на 4 без
                              остатка, то - високосный

2007	-  простой
2006	-  простой
2005	-  простой
2004	-  високосный

1896    -  високосный
1900	-  простой
1904    -  високосный
    ....
1996    -  високосный
2000	-  високосный
2004    -  високосный
    ....
2096    -  високосный
2100	-  простой
2104    -  високосный

0 года не было
был   1 год д.н.э
      1 год н.э

Поэтому начало нового тысячелетия было -
1 января 2001 года,
а не 1 января 2000 года

Коррекции календаря:
Юлианский
Грегорианский

Юлианский календарь - христианская церковь 325 г н.э.
Грегорианский был введен Oct 15, 1582 (это был Oct 5,1582 в Юлианском).

Принимался Грегорианский календарь медленно:
    Италия		1582
    Великобритания	1752
    Россия		1918
    Греция		1923

Разница в том, что xx00 - всегда считались високосными в Юлианском календаре
Сейчас разница уже - 13 дней
(эта разница действует: с 1 марта 1900 до 29 фев 2100)

Коперник родился 19 февраля 1473 года (естественно Юлианский календарь)
для XV века разница 9 дней
соответсвенно  19 + 9 = 28 февраля 1473 года по новому стилю.

  Форматы текстового представления времени

День недели

Считаем по разному
В России первый день недели - понедельник
В Англоязычных странах - Sunday

Форматы разные:
    12.01.07	// RUS:  DD.MM.YY
    01/12/07	// US:   MM/DD/YY
    12/01/07	// UK:   DD/MM/YY

    DD.MM.YYYY	Russia
    YYYY.MM.DD	Japan
    MM/DD/YYYY	US
    DD/MM/YYYY	UK

и на время:
    12:23:00	// RUS:  HH:MM:SS.msec
    23:10
    12:03am		// US:   HH:MMLL

12-часовой, 24-часовой
    AM	0:00-11:59
    PM	12:00-23:59

HTTP Cookies:	Fri, 03 Dec 2010
ISO 8601	2010-12-03 T06:23:39-0500
RFC822		Fri, 03 Dec 2010 06:23:39 EST
RFC850		Friday, 03-Dec-10 06:23:39 EST

Номер недели в году
Неделя
A)	ISO 8601:1988	та которая 4 дня
    общее правило - неделя на которой 4 или более дней принадлежит
    новому году - является его неделей номер 1 (эта та неделя которая
    включает 4 января)

B)	начинается с Sunday
C)	начинается с Monday

    начинается с 1
    (1-53)

#	День недели	сокращенно
0	Sunday		Sun		воскресение
1	Monday          Mon		понедельник
2	Tuesday         Tue		вторник
3	Wednesday       Wed		среда
4	Thursday        Thu		четверг
5	Friday          Fri		пятница
6	Saturday        Sat		суббота

               Days per month
Jan	January		31		Январь
Feb	February        28/29		Февраль
Mar	March           31		Март
Apr	April           30		Апрель
May	May             31		Май
Jun	June            30		Июнь
Jul	July            31		Июль
Aug	August          31		Август
Sep	September       30		Сентябрь
Oct	October         31		Октябрь
Nov	November        30		Ноябрь
Dec	December        31		Декабрь

Advanced:
    Корректирующие секунды:
        00:00:00

        23:59:59
        23:59:60  коректирующая секунда
        23:59:61  тоже корректирующая секунда

    по 1й секунде добавлялось в 1998 и 2005 году.

В любом случае из-за приливов вращение земли замедляется.

  Time Zone

Time Zone
    Поясное время

В Москве 15:00, в Петрапавловске-на-Камчатке полночь.

GMT	Greenwich Mean Time

EST	Eastern Standart Time (GMT-5)  US
CST     Central Standart Time (GMT-6)  US
MST	Mountain Standart Time (GMT-7) US
PST	Pasific Standart Time (GMT-8) US
HST	Hawaiian Standart Time (GMT-10) US

EST	Eastern Standart Time  (GMT+10) Австралия
CST	Central Standart Time  (GMT+9:30) Австралия

CET	Centroeuropean time (GMT+1)  вся западная европа кроме Португалии
EET     East European time  (GMT+2)

London		GMT
Moscow		GMT+03
Los Angeles	GMT-07

UTC = GMT без DST

+-HHMM

Секунды
-12	-43200
-11	-39600
-10	-36000
-9	-32400
-8	-28800
-7	-25200
-6	-21600
-5	-18000
-4	-14400
-3.5	-12600
-3	-10800
0	0
1	3600
2	7200
3	10800
3.5	12600
4	14400
4.5	16200
5	18000
5.5	19800
5.75	20700
6	21600
6.5	23400
7	25200
8	28800
9	32400
9.5	34200
10	36000
12	43200

Линия перемены дат

У нас в России есть 2 места - где сходяться сразу 3 timezone.
Так решали вопрос - где покупать водку когда поздно.
(Хотя населенных пунктов там нет).

Летнее и зимнее время
    В целях экономии электроэнергии.

    Daylight Saving Time

В разных странах переход на летнее время осуществляется в разное время
Например MSK-LA разница в зависимости от даты может быть 11 или 12 часов.

Переход на летнее время
    В 2 часа ночи - становиться 3 часа ночи

Перевод на зимнее время:
    В 3 часа ночи - снова становиться 2 час ночи

Россия:
    последнее воскресение марта (на 1 час вперед)
    последнее воскресение октября (на 1 час назад)

США
    в 2005 принят новый закон о летнем времени вступил в силу с 2007
    до 2007 - первое воскресение апреля
    c  2007 - на 3 недели раньше
    до 2007 - последнее воскресение октября
    с  2007 - первое воскресение ноября.

Проблема наследования неделимого майората и близнецов
Первый родился  - 1:49  (до перевода времени)
Второй рождился - 1:20  (после перевода времени)
в один и тот же день когда переводили время
Старшинство по нотариально заверенным показаниям акушерки.

    Время
       /     \
     UTC    Локальное

Как правило современные компьютеры имеют при инсталляции checkbox,
который показывает что время в CMOS RTC настроено как локальное или
как UTC.
Для UTC нет зимнего и летнего времени (в отличии от GMT).

NTFS хранит время в UTC.
FAT  хранит время - Local time.

Современные OS имеют функцию автокорекции времени в CMOS RTC при переходе
на/c летнее время (если RTC время стоит локальным).
В случае нескольких OS на компьютере в результате их запуска происходит
множественная коррекция времени.

Конечно лучше всего иметь время в RTC как UTC.

  Основные форматы представления времени в компьютере

Основные форматы времени
Связанны с OS и с дисковыми структурами и сетевыми пакетами

  DOS

    DOSDATE
    {
        unsigned  DayOfMonth:5;	  // 1..31
        unsigned  MonthOfYear:4;  // 1..12
        unsigned  Year:7;	  // 0..127 - means 1980..2107
    }

    DOSTIME
    {
        unsigned  SecondsDiv2:5;    // 0..29  means 0..58 seconds
        unsigned  Minutes:6;	    // 0..59
        unsigned  Hour:5;	    // 0..23
    }

  Windows NT

    64-битный тип показывающий  время в 100ns интервалах начиная
    с 1 января 1601 года (UTC)
    typedef struct _FILETIME
    {
        DWORD dwLowDateTime;
        DWORD dwHighDateTime;
    } FILETIME,

  UNIX

    struct timespec
    {
        time_t	tv_sec; 	// количество секунд начиная с 00:00:00 1 Jan 1970 GMT
        long	tv_nsec;
    }

  CDFS

    cdfs_time_date
    {
        char	NumberOfYearSince1900;		// 0..255  cover 1900..2255
        char	MonthOfYear;			// 1..12
        char	DayOfMonth;			// 1..31
        char	HourOfDay;			// 0..23
        char	MinuteOfHour;			// 0..59
        char	SecondOfMinute;			// 0..59
        char	OffsetFromGreewich;		// contain practically Timezone
    }

  UDF

    udf_timestamp
    {
        word	TypeAndTimezone;
        word	Year;				// 0..65535
        byte	Month;   			// 1..12
        byte	Day;				// 1..31
        byte	Hour;				// 0..23
        byte	Minute;				// 0..59
        byte	Second;				// 0..59
        byte	CentiSeconds;			// 0..99
        byte	HundredsOfms;			// 0..99
        byte	Millisec;			// 0..99
    }

Бывают и приватные форматы:
например Microsoft VirtualPC VHD диски считают свой timestamp
в секундах начиная с 00:00:00 1-Jan-2000.

Проблема 2000 года
Y2K problem:
Представление года в виде одного байта числом
    91	- 1991 год
    98	- 1998 год

    00	- 2000 год,

но в числовой форме - 00 < 91  - получаются ошибки.

На самом деле самое страшное что нас ждет - это конец UNIX эпохи.

Y2038	19 Jan 2038 3:14:07 UTC  = 2147483647 sec  on epoch 1-Jan-1970

  Монотонное системное время

Для работы требуется два вида времени

         Время
           /      \
 Календарное      Интервальное

Операционные системы для внутренних целей пользуются как правило
интервальным временем с момента последней загрузки.
Это основное время для внутренних синхронизаций - помому что календарное
время может быть изменено (например изменена time zone, или летнее/зимнее).

Так же есть определенные проблемы связанные с middleware - синхронизация времени
между различными компьютерами.

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

Но как правило просто меняют частоту таймера который генерирует  тики.
Как правило увеличивают/уменьшают тик не более чем на 10%.

        0           1           2           3           4           5
    |...........|...........|...........|...........|...........>  нормально
    |..........|..........|..........|..........|..........|....>  убыстрили на 10%
    |............|............|............|............|.......>  замедлили на 10%

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

Соответсвенно абсолютное время система вычисляет как:

    Время_старта_системы_абсолютное + время_работы_системы_интервальное

  Источники времени

Прочтите секции
60.3.3. PIT  и  60.3.4. RTC - на тему аппартных источников времени

RTC (Real Time Clock) встоен во все компьютеры питается от батарейки,
разрешающая способность - обычно не более 1/10 секунды.
точность невысокая - бывают случае когда за год время уползает минут на 20
(особенно если батарейка совсем плохая).
    2007 12 31   24:00:00
         12 31/30/29/28  24 60 60
Проблемы:
    Имеет время обновления в процессе которого данные не consistance

Timer - тоже есть во всех компьютерах - переодически дает прерывания, кроме
того его можно прочитать.
Прерывания обычно идут с частотой от 18.2 Hz, до 1000 Hz в зависимости от платформы
и настроек. Обычно используется как основной источник для интервального времени
операционной системы.
В отличии от RTC как правило читается атомарно
Есть и более продвинутые варианты например HPET, или специальные таймеры встроенные
в процессор (Local APIC).

TSC (Time Stamp Counter) - в современных процессорах есть специальные регистры которые
прибавляют к себе 1 каждый такт синхронизации.
К сожалению это не панацея, потому что например при перегреве процессора он может понижать
внутреннюю тактовую частоту - что отражается  на скорости обновления счетчика.

Специальный случай - Watchdog Timer.
Он работает следующим образом. После того как к нему было обращение он начинает отсчитывать
интервал времени, как интервал закончен он выдает сигнал, который как правило завязан на
сигнал RESET и осуществляет сброс машины.
Это повышает надежность - если система зависла (т.е. не обращается определенное время к
Watchdog timer), то ее сбрасывают аппаратно и она перезагружается.

Источники календарного времени:

RTC

Синхронизируем время с сервером по сети.
    Источники:
        Точные атомные часы
        Коллективные дисциплины:

Коллективные дисциплины:
    0	0	0	0	0	0
    +2	-11	-3	+5	+8	+3
   обрабытавают статистику, выбрасывают сильные отклонения.
   затем рассчитываем коррекцию

  Требования программ к временным задержкам

Какие вообще требования у программ к временным задержкам:

1) Schedule
Надо что бы функция/программа вызвалась 1-Jan-2007 в 21:43:04
Как правило это делает специализированная программа - например croт демон
Либо (если функция) то операционная система
Точность как правило не очень важна. 1/10 секунды погоды не делает.

2) Interval
Надо что бы функция вызвалась чераз 3.5 секунды
Это делает операционная система, которой говорят
Эта нить ждет объект таймера (а в объекте таймера уже стоит 3.5 cек вперед)

3) Micro Delay
Мы работаем с оборудованием, и нам надо выждать маленькое количество времени
(например 100ns, при этом если мы получим управление позже чем 200ns нам
это тоже не поможет - поэтому нам не надо, что бы нас вытесняли.
То есть работа происходит в той же нити.


81.1.1. API ДЛЯ РАБОТЫ СО ВРЕМЕНЕМ

  Арифметика времени

Есть 2 типа времени:  интервальное и реальное.

  Интервальное время

  Интервальное и реальное время

Сравнивать между собой интервальное и реальное время бесмысленно.

  Реальное время

Складывать два реальных времени - бесполезно.

  Сравнение реальных времен

В пределах одной time zone
В разных timezone
    обязательно надо учитывать Daylight saving

  Концептуальный RTL для работы со временем

По хорошему абсолютное время это пара
    Локальное время		UTC время
    TimeZone		0
к которой хороше бы добавить
       (Daylight Saving)	Yes/No
чтобы избежать множественных коррекций

  Получить интервальное время

    как правило либо это время с момента загрузки системы
    или время потраченное на выполнение нити или процесса

 UNIX

    clock_t	clock(void)		// process time
        CLOCKS_PER_SEC

        (clock_t)(-1)		если непредставимо

    int    clock_gettime(clockid_t clock_id,
                      struct timespec* ts);

    int    clock_settime(clockid_t clock_id,
                     struct timespec ts);

    clockid_t:
        CLOCK_MONOTONIC
        CLOCK_PROCESS_CPUTIME_ID
        CLOCK_REALTIME
        CLOCK_THREAD_CPUTIME_ID

 UNIX

//sys/times.h

struct	tms
{
    clock_t	tms_utime;  	// user time
    clock_t	tms_stime;      // childs user time
    clock_t	tms_cutime;     // kernel time
    clock_t	tms_cstime;     // childs kernel time
};

 Windows

    DWORD WINAPI GetTickCount(void);	// ticks in milliseconds since system
                        // was started, up to 49.7 days

    ULONGLONG WINAPI GetTickCount64(void);	// Vista

    BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
    BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
                        // отчетов в секунду

  Получить системное время

 UNIX

    time_t time(time_t* t);

 Windows

    VOID	GetSystemTime(LPSYSTEMTIME lpst)      		// UTC
    void    GetLocalTime(LPSYSTEMTIME lpSystemTime);

    typedef struct _SYSTEMTIME
    {
        WORD	wYear;
        WORD	wMonth;
        WORD	wDayOfWeek;
        WORD	wDay;
        WORD	wHour;
        WORD	wMinute;
        WORD	wSecond;
        WORD	wMilliseconds;
    } SYSTEMTIME, * LPSYSTEMTIME;

  Установить системное время

Как правило требует дополнительных привелегий

 UNIX

    int    stime(time_t* t);	// set

 Windows

    BOOL    SetSystemTime(const SYSTEMTIME* lpSystemTime);
    BOOL    SetLocalTime(const SYSTEMTIME* lpSystemTime);

  Скорректировать системное время

Требует дополнительных привелегий

 UNIX

//sys/time.h
    int adjtime(const struct timeval* delta,
            const struct timeval* olddelta);

 UNIX

//sys/timex.h

    int	adjtimex(struct timex* adj);

    struct timex!!!

 Windows

BOOL WINAPI SetSystemTimeAdjustment(
         DWORD dwTimeAdjustment,
            BOOL bTimeAdjustmentDisabled);

  Получить Timezone

    extern	int	daylight;
    extern	long	timezone;
    extern	day	*tzname[2];	// [0] = standart time
                    // [1] = dst

    void	tzset(void);		// заполняет переменные.

//	TZ enviroment variable
//set TZ=EST5EDT
//	Eastern standart time
//	5 delta
//	EDT - in daylight time

 UNIX

//sys/time.h
    int gettimeofday(struct timeval* tv,
             struct timezone* tz);

 Windows

    DWORD	GetTimeZoneInformation(LPTIME_ZONE_INFORMATION*)

    typedef struct _TIME_ZONE_INFORMATION
    {
        LONG	Bias;
        TCHAR	StandardName[32];
        SYSTEMTIME  StandardDate;
        LONG	StandardBias;
        TCHAR	DaylightName[32];
        SYSTEMTIME  DaylightDate;
        LONG	DaylightBias;
    } TIME_ZONE_INFORMATION, * LPTIME_ZONE_INFORMATION;

  Установить Timezone

Тоже требует дополнительных привелегий

 UNIX

//sys/time.h

    int settimeofday(const struct timeval* tv,
             const struct timezone* tz);

 Windows

    BOOL    SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation);

    BOOL WINAPI SetDynamicTimeZoneInformation(
        const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation);

    typedef struct _TIME_DYNAMIC_ZONE_INFORMATION
    {
        LONG Bias;
        WCHAR StandardName[32];
        SYSTEMTIME StandardDate;
        LONG StandardBias;
        WCHAR DaylightName[32];
        SYSTEMTIME DaylightDate;
        LONG DaylightBias;
        WCHAR TimeZoneKeyName[128];
        BOOLEAN DynamicDaylightTimeDisabled;
    } DYNAMIC_TIME_ZONE_INFORMATION,  *PDYNAMIC_TIME_ZONE_INFORMATION;

  Перевести абсолютное время в другую timezone

    из UTC в Local Time
    из Local Time в UTC
    (возможны варианты: в указанную time zone).

  Преобразования различных типов времени

Сравнить абсолютные времена (кто больше)
    с учетом time zone
Получить интервальное время из 2х абсолютных

    time_t	mktime(struct tm* tm);
            можно использовать арифметические преобразования
            напримем 33 день месяца - она сконвертирует

    struct tm * gmtime(const time_t* timep);                        // to UTC
    struct tm * gmtime_r(const time_t* timep, struct tm* result);

    struct tm * localtime(const time_t* timep);			// to local
    struct tm * localtime_r(const time_t* timep, struct tm * result);

    double	difftime(time_t time1, time_t time0);
            // in seconds

QNX
time.h
    void	nsec2timespec(struct timespec* timespec_p, _uint64 nsec);
    _uint64	timespec2nsec(struct timespec* timespec_p);

 UNIX

    struct tm* getdate(const char* s);

    Non-standard:
    time_t	timegm(struct tm* tp);

  Форматный ввод/вывод времени

    т.е. преобразование даты/времени в строку и обратно

Стандартный формат времени выдаваемый asctime():

    "Tue Jun 17 23:17:28 1997\n\0"

// time.h

    char*	ctime(const time_t* timep);
    char*   ctime_r(const time_t* timep, char* buf);

    char*	asctime(const struct tm* tm);
    char*	asctime_r(const struct tm* tm, char* buf);

    size_t	strftime(char*s, size_t max, char* fmt, struct tm* tp);
                            // printf analog

    %a	3-char name of weekday		'Fri'
    %A	full name of weekday            'Friday'
    %b 	3-char name of month            'Jun'
    %B	full name of month              'June'
    %c	preffered local expression of time or date (ctime()/asctime())

    %d	day of month                  (01-31)
    %D      MM/DD/YY  [C99]
    %F      YY-MM-DD  [C99]
    %g      last 2 digits of year (year based on week) [C99]
    %G      year based on week  [C99]
    %h	shortname of month [C99]

    %H	hour of day 24 hour mode      (00-23)
    %I	hour of day 12 hour mode      (00-12)
    %j	day of year (1..)             (001-366)
    %m	month    (01-12)
    %M	minute 2  (00-59)
    %p	AM or PM
    %S	seconds (0..)  (00-59)
    %U	week of year (00-53) [week 1 start first Sunday of year]
    %W	week of year (00-53) [week 1 start first Monday of year]
    %w	day of week (0-6) [sunday-saturday]
    %x	local date expression
    %X	local time expression
    %y	last 2 digits of year
    %Y	full 4digit year
    %z      offset from UTC  [C99]
    %Z	standart abbrevation for time zone or empty string if none
    %%	%

        Локализованные выражения могут меняться при  установке
        setlocate(LC_TIME, "...")

Wide:
    wcsftime(wchar_t* buf,
        size_t bufsize,
        const wchar_t* format,
        const struct tm* tmbuf);

    char*	strptime(char*s, char* fmt, struct tm* tp);	// scanf analog

Wide:
    wcsptime

  Ждать указанное число времени

    (Вообще говоря деляться на 2 категории tick-based и speen-wait).
    Delay
    MicroDelay

 UNIX

//unistd.h

    unsigned int	sleep(unsigned int seconds);

    //BSD
    void	usleep(unsigned long usec);

    //SUS
    int	usleep(useconds_t usec);

 UNIX

    struct timeval tv = { .tv_sec = 0, .tv_usec = 757 };
    select(0, NULL, NULL, NULL);

    int	nanosleep(const struct timespec* req,
              const struct timespec* rem);

    int	clock_nanosleep(clockid_t clock_id,		// POSIX
            int flags,
            const struct timespec* req,
            struct timespec* rem);

  Таймеры

Об этом в следущей секции

  Реальные интерфейсы

//time.h

    typedef long time_t;

    struct	timespec
    {
        time_t		tv_sec;
        long		tv_nsec;
    };

    struct	tm
    {
        int	tm_sec;        // 0-61
        int	tm_min;        // 0-59
        int	tm_hour;       // 0-23
        int	tm_mday;       // 1-31
        int	tm_mon;        // 0-11
        int	tm_year;       // year-1900
        int	tm_wday;       // 0-6 (sunday-saturday)
        int	tm_yday;       // day of year 0-365
        int	tm_isdst;      // if daylight saving
                       //  > 0  daylight saving
                       //  0    no daylight saving
                       //  < 0  unknown
    #ifdef	_BSD_SOURCE
        long	tm_gmtoff;     // GMT offset
        const char*  tm_zone;  // time zone name
    #endif
    };

    struct timeval
    {
        time_t		tv_sec;
        suseconds_t     tv_usec;
    };

    struct timezone
    {
        int		tz_minuteswest;
        int		tz_dsttime;	// DST correction
    };

 UNIX

// sys/time.h
// Linux extensions - macroses

    timerclear(struct timeval*)
    timerisset(struct timeval*)
    timercmp(struct timeval *t0, struct timeval* t1, operator) // only > and <
    timeradd(struct timeval* t0, struct timeval* t2, struct timeval* result)
    timersub(struct timeval* t0, struct timeval* t2, struct timeval* result)

UNIX
 ------------------------------------------------------------
        sec		usec		nsec
        time_t  	timeval		timespec
 ------------------------------------------------------------
Get time	time		gettimeofday	clock_gettime
Set time	stime		settimeofday	clock_settime
Sleep		sleep		select		nanosleep
Get
 ------------------------------------------------------------

BIOS
DOS

dos.h
    void	_dos_getdate(struct dosdate_t* date);
    unsigned _dos_setdate(struct dosdate_t* date);

    void      _dos_gettime(struct dostime_t* time);
    unsigned  _dos_settime(struct dostime_t* time);

struct	dosdate_t
{
    unsinged char	day;
    unsigned char	month;
    unsigned int	year;
    unsigned char	dayofweek;
};

struct	dostime_t
{
    unsigned char	hour;
    unsigned char	minute;
    unsigned char   second;
    unsigned char   hsecond;
};

Microsoft library

    char*	_strtime(char* time);		// hh:mm:ss


81.1.1. ПОСТРОЕНИЕ ОЧЕРЕДЕЙ СВЯЗАННЫХ СО ВРЕМЕНЕМ

Построение очередей связанных с временем:

Примерно таже проблема стоит внутри операционной системы, со списками
синхронизационных объектов ждущих временные интервалы.

Держать общую очередь ждущих объектов очень накладно, поэтому исползуют
несколько очередей. В зависимости от времени ожидания объекты ставяться в
соответсвующие очереди.
1я очередь проверяется при каждом тике (или истечении кванта).
Остальные переодически перетряхиваются, и если надо объекты переносятся в более
близкие очереди.

Например:

    +------+
    |     o|-->  очередь на ближайшую секунду
    +------+
    |     o|-->  очередь на ближайшие 10 секунд
    +------+
    |     o|-->  очередь на ближайшие 3 минуты
    +------+
    |     o|-->  очередь на ближайщие 30 минут
    +------+
    |     o|-->  очередь на всю оставшуюся жизнь
    +------+


81.1.2. ТАЙМЕРЫ

THIS SECTION IS UNDER CONSTRUCTION

  Концептуальные API

Получать сообщения с интервалом столько то времени
    Запустить
    Пауза/Продолжить
    Отменить

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

  Создание таймера

  Запуск таймера

  Получение сигнала от таймера

  Остановка таймера

  Удаление таймера

  Реальные API

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

Естественно вызов происходит в контексте процесса но не на стеке на котором выполняются
основные нити. Например в Windows вызов происходит как APC (Application Procedure Call).

 Windows

SetTimer() [Win32]
    UINT 	SetTimer(
        HWND	hwnd,
        UINT	idTimerEvent,
        UINT	uTimeOut,
        TIMERPROC tmrpc);

    VOID CALLBACK TimerProc(
        HWND	hwnd,
        UNIT	uMsj,
        UINT	idEvent,
        DWORD	dwTime);

 KillTimer() [Win32]
        BOOL 	KillTimer(
        HWND	hwnd,
        UINT	idTimer);

HANDLE WINAPI CreateWaitableTimer(
  __in          LPSECURITY_ATTRIBUTES lpTimerAttributes,
  __in          BOOL bManualReset,
  __in          LPCTSTR lpTimerName
);

HANDLE WINAPI OpenWaitableTimer(
  __in          DWORD dwDesiredAccess,
  __in          BOOL bInheritHandle,
  __in          LPCTSTR lpTimerName
);

BOOL WINAPI SetWaitableTimer(
  __in          HANDLE hTimer,
  __in          const LARGE_INTEGER* pDueTime,
  __in          LONG lPeriod,
  __in          PTIMERAPCROUTINE pfnCompletionRoutine,
  __in          LPVOID lpArgToCompletionRoutine,
  __in          BOOL fResume
);

BOOL WINAPI CancelWaitableTimer(
  __in          HANDLE hTimer
);

В OS/2 Timer ставит семафоры:

OS/2:

 DosAsyncTimer() [OS/2]
    APIRET	DosAsyncTimer(
        ULONG	ulTimerInterval,
        HSEM	hsemHandle,
        PHTIMER	pHandle);

 DosStartTimer() [OS/2]
    APIRET	DosStartTimer(
        ULONG	ulTimerInterval,
        HSEM	hsemHandle,
        PHTIMER	pHandle);

 DosStopTimer() [OS/2]
    APIRET	DosStopTimer(
        HTIMER	htimerHandle);

В UNIX используется механизм сигналов:

 UNIX

// signal.h
// unistd.h - теперь

int (* signal (int signum, void (*action) (int))) (int);

unsigned alarm(unsigned seconds);
    // return -1 on error
    // rest from previous if success

int	kill(int pid, int sig);

int	pause();	// ждет прихода сигнала
    // всегда возвращает -1
    // errno всегдя EINTR

void	sleep(unsigned seconds)
{

    oldhandler = signal(SIGALRM, handler);
    alarm(seconds);
    pause();
    signal(SIGALRM, oldhandler);
}

 UNIX

//old style
    signal(SIGALRM, SIG_DFL)
            SIG_IGN

 UNIX

// sys/time.h

struct itimerval
{
    struct timeval  it_value;
    struct timeval	it_interval;
}

result = gettimer(int which, struct timeval* val);
result = settimer(int which, const struct timeval* val,
                 struct timeval* oldval);

    // which is:
    //	ITIMER_REAL
    //	ITIMER_VIRTUAL
    //	ITIMER_PROF

Классы для работы с таймерами

Qt

class QTimer : QObject
{
    QTimer ( QObject * parent = 0 );
    ~QTimer ();
    int interval () const;
    bool isActive () const;
    bool isSingleShot () const;
    void setInterval ( int msec );
    void setSingleShot ( bool singleShot );
    int timerId () const;

public slots:
    void start ( int msec );
    void start ();
    void stop ();

public signals:
    void timeout ();

public:
    static void singleShot ( int msec, QObject * receiver, const char * member );
}


81.1.3. КЛАССЫ ДЛЯ РАБОТЫ С ВРЕМЕНЕМ

Стандартная библиотека C++ не имеет классов для работы со временем.

Что такое интересное делают 3rd party классы, что не изложено в стандартной библиотеке.
    Функции для конвертации интервального времени
        в человеческие единицы  (дни,часы,минуты итд)
        тотально в человеческие единицы (например тотально минуты)

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

    Дополнительные временные сервисы
        номер недели в году

    Календарные вещи
        является ли дата валидной
        является ли год високосным
        имена месяцев

    Расширенную поддержку timezones
        более удобную конвертацию
        информацию о состоянии Daylight saving для указанной даты времени
        интервалы которые более одного раза попадают в один и тот же local time

  MFC

class CTimeSpan
{
public:
    CTimeSpan();
    CTimeSpan(time_t time);
    CTimeSpan(LONG lDays, int nHours, int nMins, int nSecs);

    CTimeSpan(const CTimeSpan& timeSpanSrc);
    const CTimeSpan& operator=(const CTimeSpan& timeSpanSrc);

    LONG GetDays() const;   // total # of days
    LONG GetTotalHours() const;
    int GetHours() const;
    LONG GetTotalMinutes() const;
    int GetMinutes() const;
    LONG GetTotalSeconds() const;
    int GetSeconds() const;

    CTimeSpan operator-(CTimeSpan timeSpan) const;
    CTimeSpan operator+(CTimeSpan timeSpan) const;
    const CTimeSpan& operator+=(CTimeSpan timeSpan);
    const CTimeSpan& operator-=(CTimeSpan timeSpan);
    BOOL operator==(CTimeSpan timeSpan) const;
    BOOL operator!=(CTimeSpan timeSpan) const;
    BOOL operator<(CTimeSpan timeSpan) const;
    BOOL operator>(CTimeSpan timeSpan) const;
    BOOL operator<=(CTimeSpan timeSpan) const;
    BOOL operator>=(CTimeSpan timeSpan) const;

    CString Format(LPCTSTR pFormat) const;
    CString Format(UINT nID) const;

    friend CArchive& AFXAPI operator<<(CArchive& ar, CTimeSpan timeSpan);
    friend CArchive& AFXAPI operator>>(CArchive& ar, CTimeSpan& rtimeSpan);

private:
    time_t m_timeSpan;
    friend class CTime;
};

class CTime
{
public:

    static CTime PASCAL GetCurrentTime();

    CTime();
    CTime(time_t time);
    CTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec,
        int nDST = -1);
    CTime(WORD wDosDate, WORD wDosTime, int nDST = -1);
    CTime(const CTime& timeSrc);

    CTime(const SYSTEMTIME& sysTime, int nDST = -1);
    CTime(const FILETIME& fileTime, int nDST = -1);
    const CTime& operator=(const CTime& timeSrc);
    const CTime& operator=(time_t t);

    struct tm* GetGmtTm(struct tm* ptm = NULL) const;
    struct tm* GetLocalTm(struct tm* ptm = NULL) const;
    BOOL GetAsSystemTime(SYSTEMTIME& timeDest) const;

    time_t GetTime() const;
    int GetYear() const;
    int GetMonth() const;       // month of year (1 = Jan)
    int GetDay() const;         // day of month
    int GetHour() const;
    int GetMinute() const;
    int GetSecond() const;
    int GetDayOfWeek() const;   // 1=Sun, 2=Mon, ..., 7=Sat

    CTimeSpan operator-(CTime time) const;
    CTime operator-(CTimeSpan timeSpan) const;
    CTime operator+(CTimeSpan timeSpan) const;
    const CTime& operator+=(CTimeSpan timeSpan);
    const CTime& operator-=(CTimeSpan timeSpan);
    BOOL operator==(CTime time) const;
    BOOL operator!=(CTime time) const;
    BOOL operator<(CTime time) const;
    BOOL operator>(CTime time) const;
    BOOL operator<=(CTime time) const;
    BOOL operator>=(CTime time) const;

    // formatting using "C" strftime
    CString Format(LPCTSTR pFormat) const;
    CString FormatGmt(LPCTSTR pFormat) const;
    CString Format(UINT nFormatID) const;
    CString FormatGmt(UINT nFormatID) const;

    friend CArchive& AFXAPI operator<<(CArchive& ar, CTime time);
    friend CArchive& AFXAPI operator>>(CArchive& ar, CTime& rtime);

private:
    time_t m_time;
};

  Qt

    QDate
    QTime
    QDateTime

class QDate
{
public:
    QDate ();
    QDate ( int y, int m, int d );
    QDate addDays ( int ndays ) const;
    QDate addMonths ( int nmonths ) const;
    QDate addYears ( int nyears ) const;
    int day () const;
    int dayOfWeek () const;
    int dayOfYear () const;
    int daysInMonth () const;
    int daysInYear () const;
    int daysTo ( const QDate & d ) const;
    bool isNull () const;
    bool isValid () const;
    int month () const;
    bool setDate ( int year, int month, int day );
    int toJulianDay () const;
    QString toString ( const QString & format ) const;
    QString toString ( Qt::DateFormat format = Qt::TextDate ) const;
    int weekNumber ( int * yearNumber = 0 ) const;
    int year () const;
    bool operator!= ( const QDate & d ) const;
    bool operator< ( const QDate & d ) const;
    bool operator<= ( const QDate & d ) const;
    bool operator== ( const QDate & d ) const;
    bool operator> ( const QDate & d ) const;
    bool operator>= ( const QDate & d ) const;

static	QDate currentDate ();
static	QDate fromJulianDay ( int jd );
static	QDate fromString ( const QString & string, Qt::DateFormat format = Qt::TextDate );
static	QDate fromString ( const QString & string, const QString & format );
static	bool isLeapYear ( int year );
static	bool isValid ( int year, int month, int day );
static	QString longDayName ( int weekday );
static	QString longMonthName ( int month );
static	QString shortDayName ( int weekday );
static	QString shortMonthName ( int month );
};

QDataStream & operator<< ( QDataStream & out, const QDate & date )
QDataStream & operator>> ( QDataStream & in, QDate & date )

class QDateTime
{
public:
    QDateTime ();
    QDateTime ( const QDate & date );
    QDateTime ( const QDate & date, const QTime & time, Qt::TimeSpec spec = Qt::LocalTime );
    QDateTime ( const QDateTime & other );
    ~QDateTime ();
    QDateTime addDays ( int ndays ) const;
    QDateTime addMSecs ( qint64 msecs ) const;
    QDateTime addMonths ( int nmonths ) const;
    QDateTime addSecs ( int nsecs ) const;
    QDateTime addYears ( int nyears ) const;
    QDate date () const;
    int daysTo ( const QDateTime & other ) const;
    bool isNull () const;
    bool isValid () const;
    int secsTo ( const QDateTime & other ) const;
    void setDate ( const QDate & date );
    void setTime ( const QTime & time );
    void setTimeSpec ( Qt::TimeSpec spec );
    void setTime_t ( uint seconds );
    QTime time () const;
    Qt::TimeSpec timeSpec () const;
    QDateTime toLocalTime () const;
    QString toString ( const QString & format ) const;
    QString toString ( Qt::DateFormat format = Qt::TextDate ) const;
    QDateTime toTimeSpec ( Qt::TimeSpec specification ) const;
    uint toTime_t () const;
    QDateTime toUTC () const;
    bool operator!= ( const QDateTime & other ) const;
    bool operator< ( const QDateTime & other ) const;
    bool operator<= ( const QDateTime & other ) const;
    QDateTime & operator= ( const QDateTime & other );
    bool operator== ( const QDateTime & other ) const;
    bool operator> ( const QDateTime & other ) const;
    bool operator>= ( const QDateTime & other ) const;

static	QDateTime currentDateTime ();
static	QDateTime fromString ( const QString & string, Qt::DateFormat format = Qt::TextDate );
static	QDateTime fromString ( const QString & string, const QString & format );
static	QDateTime fromTime_t ( uint seconds );
};

class QTime
{
public:
    QTime ();
    QTime ( int h, int m, int s = 0, int ms = 0 );
    QTime addMSecs ( int ms ) const;
    QTime addSecs ( int nsecs ) const;
    int elapsed () const;
    int hour () const;
    bool isNull () const;
    bool isValid () const;
    int minute () const;
    int msec () const;
    int msecsTo ( const QTime & t ) const;
    int restart ();
    int second () const;
    int secsTo ( const QTime & t ) const;
    bool setHMS ( int h, int m, int s, int ms = 0 );
    void start ();
    QString toString ( const QString & format ) const;
    QString toString ( Qt::DateFormat f = Qt::TextDate ) const;
    bool operator!= ( const QTime & t ) const;
    bool operator< ( const QTime & t ) const;
    bool operator<= ( const QTime & t ) const;
    bool operator== ( const QTime & t ) const;
    bool operator> ( const QTime & t ) const;
    bool operator>= ( const QTime & t ) const;

static QTime currentTime ();
static QTime fromString ( const QString & string, Qt::DateFormat format = Qt::TextDate );
static QTime fromString ( const QString & string, const QString & format );
static bool isValid ( int h, int m, int s, int ms = 0 );
};

  C#

DateTime
TimeSpan

DateTimeOffset
    like DateTime

  DateTime

class DateTime
{
public DateTime(long ticks);
public DateTime(long ticks, DateTimeKind kind);
public DateTime(int year, int month, int day);
public DateTime(int year, int month, int day, Calendar calendar);
public DateTime(int year, int month, int day,
        int hour, int minute,int second);
public DateTime(int year, int month, int day,
        int hour, int minute,int second, DateTimeKind kind);
public DateTime(int year, int month, int day,
        int hour, int minute,int second, Calendar calendar);
public DateTime(int year, int month, int day,
        int hour, int minute,int second, int millisecond);
public DateTime(int year, int month, int day,
        int hour, int minute,int second,
        int millisecond, DateTimeKind kind);
public DateTime(int year, int month, int day,
        int hour, int minute,int second,
        int millisecond, Calendar calendar);
public DateTime(int year, int month, int day,
        int hour, int minute, int second,
        int millisecond, Calendar calendar, DateTimeKind kind);

public DateTime Add(TimeSpan value);
public DateTime AddDays(double value);
public DateTime AddHours(double value);
public DateTime AddMilliseconds(double value);
public DateTime AddMinutes(double value);
public DateTime AddMonths(int months);
public DateTime AddSeconds(double value);
public DateTime AddTicks(long value);
public DateTime AddYears(int value);

public static int Compare(DateTime t1, DateTime t2);
public int CompareTo(DateTime value);
public bool Equals(DateTime value);
public static bool Equals(DateTime t1, DateTime t2);

public static int DaysInMonth(int year,int month);

public static DateTime FromBinary(long dateData);
public static DateTime FromFileTime(long fileTime);
public static DateTime FromFileTimeUtc(long fileTime);
public static DateTime FromOADate(double d);  // OLE Automation Date

public string[] GetDateTimeFormats();
public string[] GetDateTimeFormats(char format);
public string[] GetDateTimeFormats(IFormatProvider provider);
public string[] GetDateTimeFormats(char format,	IFormatProvider provider);

public bool IsDaylightSavingTime();
public static bool IsLeapYear(int year);

public static DateTime Parse(string s);
public static DateTime Parse(string s, IFormatProvider provider);
public static DateTime Parse(string s, IFormatProvider provider,
                 DateTimeStyles styles);
public static DateTime ParseExact(string s, string format,
                    IFormatProvider provider);
public static DateTime ParseExact(string s, string format,
                     IFormatProvider provider, DateTimeStyles style);
public static DateTime ParseExact(string s, string[] formats,
                    IFormatProvider provider, DateTimeStyles style);

public static DateTime SpecifyKind(DateTime value, DateTimeKind kind);

public TimeSpan Subtract(DateTime value);
public DateTime Subtract(TimeSpan value);

public DateTime ToLocalTime();
public DateTime ToUniversalTime();

public long ToBinary();
public long ToFileTime();
public long ToFileTimeUtc();
public string ToLongDateString();
public string ToLongTimeString();
public double ToOADate();
public string ToShortDateString();
public string ToShortTimeString();

public override string ToString();
public string ToString(IFormatProvider provider);
public string ToString(string format);
public string ToString(string format,	IFormatProvider provider);

public static bool TryParse(string s, out DateTime result);
public static bool TryParse(string s, IFormatProvider provider,
                DateTimeStyles styles, out DateTime result);
public static bool TryParseExact(string s, string format,
                IFormatProvider provider,
                               DateTimeStyles style,
                out DateTime result);
public static bool TryParseExact(string s, string[] formats,
                IFormatProvider provider,
                DateTimeStyles style,
                out DateTime result);

public static DateTime operator +(DateTime d,TimeSpan t);
public static bool operator ==(DateTime d1, DateTime d2);
public static bool operator >(DateTime t1, DateTime t2);
public static bool operator >=(DateTime t1, DateTime t2);
public static bool operator !=(DateTime d1, DateTime d2);
public static bool operator <(DateTime t1, DateTime t2);
public static bool operator <=(DateTime t1, DateTime t2);
public static TimeSpan operator -(DateTime d1, DateTime d2);
public static DateTime operator -(DateTime d, TimeSpan t);

public static readonly DateTime MaxValue;
public static readonly DateTime MinValue;
public DateTime Date { get; }
public int Day { get; }
public DayOfWeek DayOfWeek { get; }
public int DayOfYear { get; }
public int Hour { get; }
public DateTimeKind Kind { get; }
    Unspecified
    Utc
    Local
public int Millisecond { get; }
public int Minute { get; }
public int Month { get; }
public static DateTime Now { get; }
public int Second { get; }
public long Ticks { get; }
public TimeSpan TimeOfDay { get; }
public static DateTime Today { get; }
public static DateTime UtcNow { get; }
public int Year { get; }
}

  TimeSpan

class TimeSpan
{
public TimeSpan(long ticks);
public TimeSpan(int hours, int minutes,	int seconds);
public TimeSpan(int days, int hours, int minutes, int seconds);
public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds);

public TimeSpan Add(TimeSpan ts);
public static int Compare(TimeSpan t1,	TimeSpan t2);
public int CompareTo(TimeSpan value);
public TimeSpan Duration();
public bool Equals(TimeSpan obj);
public static bool Equals(TimeSpan t1,	TimeSpan t2);

public static TimeSpan FromDays(double value);
public static TimeSpan FromHours(double value);
public static TimeSpan FromMilliseconds(double value);
public static TimeSpan FromMinutes(double value);
public static TimeSpan FromSeconds(double value);
public static TimeSpan FromTicks(long value);
public TimeSpan Negate();
public static TimeSpan Parse(string s);
public TimeSpan Subtract(TimeSpan ts);
public override string ToString();
public static bool TryParse(string s, out TimeSpan result);

public static TimeSpan operator +(TimeSpan t1, TimeSpan t2);
public static bool operator ==(TimeSpan t1, TimeSpan t2);
public static bool operator >(TimeSpan t1, TimeSpan t2);
public static bool operator >=(TimeSpan t1, TimeSpan t2);
public static bool operator !=(TimeSpan t1, TimeSpan t2);
public static bool operator <(TimeSpan t1, TimeSpan t2);
public static bool operator <=(TimeSpan t1, TimeSpan t2);
public static TimeSpan operator -(TimeSpan t1, TimeSpan t2);
public static TimeSpan operator -(TimeSpan t);
public static TimeSpan operator +(TimeSpan t);

public static readonly TimeSpan MaxValue;
public static readonly TimeSpan MinValue;
public const long TicksPerDay;
public const long TicksPerHour;
public const long TicksPerMillisecond;
public const long TicksPerMinute;
public const long TicksPerSecond;
public static readonly TimeSpan Zero;
public int Days { get; }
public int Hours { get; }
public int Milliseconds { get; }
public int Minutes { get; }
public int Seconds { get; }
public long Ticks { get; }
public double TotalDays { get; }
public double TotalHours { get; }
public double TotalMilliseconds { get; }
public double TotalMinutes { get; }
public double TotalSeconds { get; }
}

  TimeZone

class TimeZone
{
protected TimeZone()

public virtual bool Equals(Object obj);
public abstract DaylightTime GetDaylightChanges(int year);
public abstract TimeSpan GetUtcOffset(DateTime time);
public virtual bool IsDaylightSavingTime(DateTime time);
public static bool IsDaylightSavingTime(DateTime time,DaylightTime daylightTimes);
public virtual DateTime ToLocalTime(DateTime time);

public virtual string ToString();
public virtual DateTime ToUniversalTime(DateTime time);
public static TimeZone CurrentTimeZone { get; }
public abstract string DaylightName { get; }
public abstract string StandardName { get; }
}

  TimeZoneInfo

class TimeZoneInfo
{
public static void ClearCachedData();
public static DateTime ConvertTime(DateTime dateTime,
                      TimeZoneInfo destinationTimeZone);
public static DateTimeOffset ConvertTime(DateTimeOffset dateTimeOffset,
                   TimeZoneInfo destinationTimeZone);
public static DateTime ConvertTime(DateTime dateTime,
                   TimeZoneInfo sourceTimeZone,
                   TimeZoneInfo destinationTimeZone);
public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime,
                     string destinationTimeZoneId);
public static DateTimeOffset ConvertTimeBySystemTimeZoneId(
                   DateTimeOffset dateTimeOffset,
                   string destinationTimeZoneId);
public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime,
                      string sourceTimeZoneId,
                   string destinationTimeZoneId);

public static DateTime ConvertTimeFromUtc(DateTime dateTime,
                TimeZoneInfo destinationTimeZone);
public static DateTime ConvertTimeToUtc(DateTime dateTime);
public static DateTime ConvertTimeToUtc(DateTime dateTime,
                    TimeZoneInfo sourceTimeZone);
public static TimeZoneInfo CreateCustomTimeZone(string id,
                TimeSpan baseUtcOffset,
                          string displayName,
                string standardDisplayName);
public static TimeZoneInfo CreateCustomTimeZone(string id,
                TimeSpan baseUtcOffset,
                        string displayName,
                string standardDisplayName,
                string daylightDisplayName,
                TimeZoneInfo.AdjustmentRule[] adjustmentRules);
public static TimeZoneInfo CreateCustomTimeZone(string id,
                TimeSpan baseUtcOffset,
                    string displayName,
                string standardDisplayName,
                string daylightDisplayName,
                TimeZoneInfo.AdjustmentRule[] adjustmentRules,
                bool disableDaylightSavingTime);
public bool Equals(TimeZoneInfo other);
public static TimeZoneInfo FindSystemTimeZoneById(string id);
public TimeZoneInfo.AdjustmentRule[] GetAdjustmentRules();
public TimeSpan[] GetAmbiguousTimeOffsets(DateTime dateTime);
public TimeSpan[] GetAmbiguousTimeOffsets(DateTimeOffset dateTimeOffset);
public static ReadOnlyCollection GetSystemTimeZones();
public TimeSpan GetUtcOffset(DateTime dateTime);
public TimeSpan GetUtcOffset(DateTimeOffset dateTimeOffset);
public bool HasSameRules(TimeZoneInfo other);
public bool IsAmbiguousTime(DateTime dateTime);
public bool IsAmbiguousTime(DateTimeOffset dateTimeOffset);
public bool IsDaylightSavingTime(DateTime dateTime);
public bool IsDaylightSavingTime(DateTimeOffset dateTimeOffset);
public bool IsInvalidTime(DateTime dateTime);

public override string ToString();

public TimeSpan BaseUtcOffset { get; }
public string DaylightName { get; }
public string DisplayName { get; }
public string Id { get; }
public static TimeZoneInfo Local { get; }
public string StandardName { get; }
public bool SupportsDaylightSavingTime { get; }
public static TimeZoneInfo Utc { get; }
}

  TimeZoneInfo.AdjustmentRule

class TimeZoneInfo.AdjustmentRule
{
public static TimeZoneInfo.AdjustmentRule CreateAdjustmentRule(
    DateTime dateStart,
    DateTime dateEnd,
    TimeSpan daylightDelta,
    TimeZoneInfo.TransitionTime daylightTransitionStart,
    TimeZoneInfo.TransitionTime daylightTransitionEnd);

public bool Equals(TimeZoneInfo.AdjustmentRule other);

public virtual string ToString();
public DateTime DateEnd { get; }
public DateTime DateStart { get; }
public TimeSpan DaylightDelta { get; }
public TimeZoneInfo.TransitionTime DaylightTransitionEnd { get; }
public TimeZoneInfo.TransitionTime DaylightTransitionStart { get; }
}

  TimeZoneInfo.TransitionTime

class TimeZoneInfo.TransitionTime
{
public static TimeZoneInfo.TransitionTime CreateFixedDateRule(
    DateTime timeOfDay,
    int month,
    int day);

public static TimeZoneInfo.TransitionTime CreateFloatingDateRule(
    DateTime timeOfDay,
    int month,
    int week,
    DayOfWeek dayOfWeek);

public bool Equals(TimeZoneInfo.TransitionTime other);

public override string ToString();
public static bool operator ==(TimeZoneInfo.TransitionTime left,
                   TimeZoneInfo.TransitionTime right);

public static bool operator !=(TimeZoneInfo.TransitionTime left,
                   TimeZoneInfo.TransitionTime right);
public int Day { get; }
public DayOfWeek DayOfWeek { get; }
public bool IsFixedDateRule { get; }
public int Month { get; }
public DateTime TimeOfDay { get; }
public int Week { get; }		// week of month
}


81.1.4. ИНФОРМАЦИЯ О TIME ZONES

Ниже приведена информация о существующих time zones.
Информация приведена как есть, чисто как пища для размышлений:

------------------------------------------------------------------
UTC
(UTC) Время в формате UTC
Время в формате UTC
00:00:00
False
-----------------------
GMT Standard Time
(UTC) Дублин, Лиссабон, Лондон, Эдинбург
GMT - время по Гринвичу (лето)
00:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 01:00:00
End   : The last Sunday in Октябрь at 02:00:00
-----------------------
Morocco Standard Time
(UTC) Касабланка
Марокко (лето)
00:00:00
True
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The last Saturday in Май at 23:59:59.9990000
End   : The last Sunday in Август at 23:59:59.9990000
--
Rule applies from 01.01.2009 0:00:00 to 31.12.2009 0:00:00
Delta : 01:00:00
Start : The last Sunday in Май at 23:59:59.9990000
End   : The third Thursday in Август at 23:59:59.9990000
-----------------------
Greenwich Standard Time
(UTC) Монровия, Рейкьявик
Время по Гринвичу (лето)
00:00:00
False
-----------------------
W. Europe Standard Time
(UTC+01:00) Амстердам, Берлин, Берн, Вена, Рим, Стокгольм
Западная Европа (лето)
01:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Central Europe Standard Time
(UTC+01:00) Белград, Братислава, Будапешт, Любляна, Прага
Центральная Европа (лето)
01:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Romance Standard Time
(UTC+01:00) Брюссель, Копенгаген, Мадрид, Париж
Романское время (лето)
01:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Central European Standard Time
(UTC+01:00) Варшава, Загреб, Сараево, Скопье
Центральноевропейский (лето)
01:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
W. Central Africa Standard Time
(UTC+01:00) Западная Центральная Африка
Западная Центр. Африка (лето)
01:00:00
False
-----------------------
Jordan Standard Time
(UTC+02:00) Амман
Иорданское время (лето)
02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The last Thursday in Март at 00:00:00
End   : The last Friday in Сентябрь at 01:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Thursday in Март at 23:59:59.9990000
End   : The last Friday in Октябрь at 01:00:00
-----------------------
GTB Standard Time
(UTC+02:00) Афины, Бухарест, Стамбул
Греция, Турция (лето)
02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 03:00:00
End   : The last Sunday in Октябрь at 04:00:00
-----------------------
Middle East Standard Time
(UTC+02:00) Бейрут
Ливанское время (лето)
02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 00:00:00
End   : The last Sunday in Октябрь at 00:00:00
-----------------------
FLE Standard Time
(UTC+02:00) Вильнюс, Киев, Рига, София, Таллин, Хельсинки
Финляндия (лето)
02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 03:00:00
End   : The last Sunday in Октябрь at 04:00:00
-----------------------
Namibia Standard Time
(UTC+02:00) Виндхук
Намибийское время (лето)
02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : -01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The first Sunday in Сентябрь at 02:00:00
-----------------------
Israel Standard Time
(UTC+02:00) Иерусалим
Иерусалимское время (лето)
02:00:00
True
--
Rule applies from 01.01.2005 0:00:00 to 31.12.2005 0:00:00
Delta : 01:00:00
Start : The first Friday in Апрель at 02:00:00
End   : The second Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2006 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The first Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The third Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The first Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2009 0:00:00 to 31.12.2009 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The last Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2010 0:00:00 to 31.12.2010 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The second Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2011 0:00:00 to 31.12.2011 0:00:00
Delta : 01:00:00
Start : The first Friday in Апрель at 02:00:00
End   : The first Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2012 0:00:00 to 31.12.2012 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The fourth Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2013 0:00:00 to 31.12.2013 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The second Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2014 0:00:00 to 31.12.2014 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The fourth Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2015 0:00:00 to 31.12.2015 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The third Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2016 0:00:00 to 31.12.2016 0:00:00
Delta : 01:00:00
Start : The first Friday in Апрель at 02:00:00
End   : The second Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2017 0:00:00 to 31.12.2017 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The fourth Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2018 0:00:00 to 31.12.2018 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The third Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2019 0:00:00 to 31.12.2019 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The first Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2020 0:00:00 to 31.12.2020 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The fourth Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2021 0:00:00 to 31.12.2021 0:00:00
Delta : 01:00:00
Start : The last Friday in Март at 02:00:00
End   : The second Sunday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2022 0:00:00 to 31.12.2022 0:00:00
Delta : 01:00:00
Start : The first Friday in Апрель at 02:00:00
End   : The first Sunday in Октябрь at 02:00:00
-----------------------
Egypt Standard Time
(UTC+02:00) Каир
Египетское время (лето)
02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2005 0:00:00
Delta : 01:00:00
Start : The last Friday in Апрель at 00:00:00
End   : The last Thursday in Сентябрь at 23:59:59.9990000
--
Rule applies from 01.01.2006 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The last Friday in Апрель at 00:00:00
End   : The third Thursday in Сентябрь at 23:59:59.9990000
--
Rule applies from 01.01.2007 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The last Thursday in Апрель at 23:59:59.9990000
End   : The first Thursday in Сентябрь at 23:59:59.9990000
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The last Thursday in Апрель at 23:59:59.9990000
End   : The last Thursday in Август at 23:59:59.9990000
--
Rule applies from 01.01.2009 0:00:00 to 31.12.2009 0:00:00
Delta : 01:00:00
Start : The fourth Thursday in Апрель at 23:59:59.9990000
End   : The last Thursday in Сентябрь at 23:59:59.9990000
--
Rule applies from 01.01.2010 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Thursday in Апрель at 23:59:59.9990000
End   : The last Thursday in Сентябрь at 23:59:59.9990000
-----------------------
E. Europe Standard Time
(UTC+02:00) Минск
Восточная Европа (лето)
02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
South Africa Standard Time
(UTC+02:00) Хараре, Претория
Южная Африка (лето)
02:00:00
False
-----------------------
Arabic Standard Time
(UTC+03:00) Багдад
Багдадское время (лето)
03:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 03:00:00
End   : The first Sunday in Октябрь at 04:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 03:00:00
End   : The first Monday in Октябрь at 04:00:00
-----------------------
Russian Standard Time
(UTC+03:00) Волгоград, Москва, Санкт-Петербург
Московское время (лето)
03:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Arab Standard Time
(UTC+03:00) Кувейт, Эр-Рияд
Саудовское время (лето)
03:00:00
False
-----------------------
E. Africa Standard Time
(UTC+03:00) Найроби
Восточная Африка (лето)
03:00:00
False
-----------------------
Georgian Standard Time
(UTC+03:00) Тбилиси
Грузинское время (лето)
03:00:00
False
-----------------------
Iran Standard Time
(UTC+03:30) Тегеран
Иранское время (лето)
03:30:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2005 0:00:00
Delta : 01:00:00
Start : The first Sunday in Март at 02:00:00
End   : The fourth Tuesday in Сентябрь at 02:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The third Thursday in Март at 23:59:59.9990000
End   : The third Saturday in Сентябрь at 23:59:59.9990000
--
Rule applies from 01.01.2009 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The third Saturday in Март at 23:59:59.9990000
End   : The third Monday in Сентябрь at 23:59:59.9990000
-----------------------
Arabian Standard Time
(UTC+04:00) Абу-Даби, Мускат
Арабское время (лето)
04:00:00
False
-----------------------
Azerbaijan Standard Time
(UTC+04:00) Баку
Азербайджанское время (лето)
04:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 04:00:00
End   : The last Sunday in Октябрь at 05:00:00
-----------------------
Caucasus Standard Time
(UTC+04:00) Ереван
Кавказское время (лето)
04:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Mauritius Standard Time
(UTC+04:00) Порт-Луи
Маврикий (лето)
04:00:00
True
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The last Sunday in Октябрь at 02:00:00
End   : The first Tuesday in Январь at 00:00:00
--
Rule applies from 01.01.2009 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Октябрь at 02:00:00
End   : The last Sunday in Март at 02:00:00
-----------------------
Afghanistan Standard Time
(UTC+04:30) Кабул
Афганское время (лето)
04:30:00
False
-----------------------
Ekaterinburg Standard Time
(UTC+05:00) Екатеринбург
Уральское время (лето)
05:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Pakistan Standard Time
(UTC+05:00) Исламабад, Карачи
Пакистан (лето)
05:00:00
True
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The last Saturday in Май at 23:59:59.9990000
End   : The last Friday in Октябрь at 23:59:59.9990000
--
Rule applies from 01.01.2009 0:00:00 to 31.12.2009 0:00:00
Delta : 01:00:00
Start : The second Tuesday in Апрель at 23:59:59.9990000
End   : The last Saturday in Октябрь at 23:59:59.9990000
-----------------------
West Asia Standard Time
(UTC+05:00) Ташкент
Западная Азия (лето)
05:00:00
False
-----------------------
India Standard Time
(UTC+05:30) Колката, Мумбаи, Нью-Дели, Ченнай
Индийское время (лето)
05:30:00
False
-----------------------
Sri Lanka Standard Time
(UTC+05:30) Шри-Джаявардене-пура-Котте
Шри-Ланка (лето)
05:30:00
False
-----------------------
Nepal Standard Time
(UTC+05:45) Катманду
Непальское время (лето)
05:45:00
False
-----------------------
N. Central Asia Standard Time
(UTC+06:00) Алматы, Новосибирск
Северная Центр. Азия (лето)
06:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Central Asia Standard Time
(UTC+06:00) Астана, Дака
Центральная Азия (лето)
06:00:00
False
-----------------------
Myanmar Standard Time
(UTC+06:30) Янгон
Мьянмарское время (лето)
06:30:00
False
-----------------------
SE Asia Standard Time
(UTC+07:00) Бангкок, Джакарта, Ханой
Юго-Восточная Азия (лето)
07:00:00
False
-----------------------
North Asia Standard Time
(UTC+07:00) Красноярск
Красноярское время (лето)
07:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
China Standard Time
(UTC+08:00) Гонконг, Пекин, Урумчи, Чунцин
Китайское время (лето)
08:00:00
False
-----------------------
North Asia East Standard Time
(UTC+08:00) Иркутск, Улан-Батор
Иркутское время (лето)
08:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Singapore Standard Time
(UTC+08:00) Куала-Лумпур, Сингапур
Малайское время (лето)
08:00:00
False
-----------------------
W. Australia Standard Time
(UTC+08:00) Перт
Западная Австралия (лето)
08:00:00
True
--
Rule applies from 01.01.2006 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Декабрь at 02:00:00
End   : The first Sunday in Январь at 00:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Октябрь at 02:00:00
End   : The last Sunday in Март at 03:00:00
-----------------------
Taipei Standard Time
(UTC+08:00) Тайбэй
Тайваньское время (лето)
08:00:00
False
-----------------------
Tokyo Standard Time
(UTC+09:00) Осака, Саппоро, Токио
Токийское время (лето)
09:00:00
False
-----------------------
Korea Standard Time
(UTC+09:00) Сеул
Корейское время (лето)
09:00:00
False
-----------------------
Yakutsk Standard Time
(UTC+09:00) Якутск
Якутское время (лето)
09:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Cen. Australia Standard Time
(UTC+09:30) Аделаида
Центрально-Австралийский (лето)
09:30:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The last Sunday in Октябрь at 02:00:00
End   : The last Sunday in Март at 03:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The first Sunday in Октябрь at 02:00:00
End   : The first Sunday in Апрель at 03:00:00
-----------------------
AUS Central Standard Time
(UTC+09:30) Дарвин
Центральная Австралия (лето)
09:30:00
False
-----------------------
E. Australia Standard Time
(UTC+10:00) Брисбен
Восточная Австралия (лето)
10:00:00
False
-----------------------
Vladivostok Standard Time
(UTC+10:00) Владивосток
Владивосток (лето)
10:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
West Pacific Standard Time
(UTC+10:00) Гуам, Порт-Морсби
Западно-тихоокеанский (лето)
10:00:00
False
-----------------------
AUS Eastern Standard Time
(UTC+10:00) Канберра, Мельбурн, Сидней
Сиднейское время (лето)
10:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The last Sunday in Октябрь at 02:00:00
End   : The last Sunday in Март at 03:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The first Sunday in Октябрь at 02:00:00
End   : The first Sunday in Апрель at 03:00:00
-----------------------
Tasmania Standard Time
(UTC+10:00) Хобарт
Тасманийское время (лето)
10:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The first Sunday in Октябрь at 02:00:00
End   : The last Sunday in Март at 03:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The first Sunday in Октябрь at 02:00:00
End   : The first Sunday in Апрель at 03:00:00
-----------------------
Central Pacific Standard Time
(UTC+11:00) Магадан, Нов. Каледония, Соломоновы о-ва
Центрально-тихоокеанский (лето)
11:00:00
False
-----------------------
New Zealand Standard Time
(UTC+12:00) Веллингтон, Окленд
Новозеландское время (лето)
12:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Октябрь at 02:00:00
End   : The third Sunday in Март at 03:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The last Sunday in Сентябрь at 02:00:00
End   : The third Sunday in Март at 03:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Сентябрь at 02:00:00
End   : The first Sunday in Апрель at 03:00:00
-----------------------
Fiji Standard Time
(UTC+12:00) Маршалловы о-ва, Фиджи
Фиджи (лето)
12:00:00
False
-----------------------
Kamchatka Standard Time
(UTC+12:00) Петропавловск-Камчатский
Камчатка (лето)
12:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Tonga Standard Time
(UTC+13:00) Нукуалофа
Тонга (лето)
13:00:00
False
-----------------------
Azores Standard Time
(UTC-01:00) Азорские о-ва
Азорское время (лето)
-01:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Октябрь at 03:00:00
-----------------------
Cape Verde Standard Time
(UTC-01:00) О-ва Зеленого Мыса
О-ва Зеленого мыса (лето)
-01:00:00
False
-----------------------
Mid-Atlantic Standard Time
(UTC-02:00) Среднеатлантическое время
Средняя Атлантика (лето)
-02:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Sunday in Март at 02:00:00
End   : The last Sunday in Сентябрь at 02:00:00
-----------------------
E. South America Standard Time
(UTC-03:00) Бразилия
Восточное Ю-Ам. время (лето)
-03:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Ноябрь at 00:00:00
End   : The second Sunday in Февраль at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The second Sunday in Октябрь at 00:00:00
End   : The last Sunday in Февраль at 00:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The third Sunday in Февраль at 00:00:00
--
Rule applies from 01.01.2009 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Февраль at 23:59:59.9990000
-----------------------
Argentina Standard Time
(UTC-03:00) Буэнос-Айрес
Аргентина (лето)
-03:00:00
True
--
Rule applies from 01.01.2007 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The last Sunday in Декабрь at 00:00:00
End   : The first Monday in Январь at 00:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The third Sunday in Март at 00:00:00
--
Rule applies from 01.01.2009 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
-----------------------
Greenland Standard Time
(UTC-03:00) Гренландия
Гренландское время (лето)
-03:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2009 0:00:00 to 31.12.2009 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The fourth Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2010 0:00:00 to 31.12.2010 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2011 0:00:00 to 31.12.2011 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2012 0:00:00 to 31.12.2012 0:00:00
Delta : 01:00:00
Start : The fourth Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2013 0:00:00 to 31.12.2013 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2014 0:00:00 to 31.12.2014 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2015 0:00:00 to 31.12.2015 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The fourth Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2016 0:00:00 to 31.12.2016 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2017 0:00:00 to 31.12.2017 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2018 0:00:00 to 31.12.2018 0:00:00
Delta : 01:00:00
Start : The fourth Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2019 0:00:00 to 31.12.2019 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2020 0:00:00 to 31.12.2020 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The fourth Saturday in Октябрь at 23:00:00
--
Rule applies from 01.01.2021 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The last Saturday in Март at 22:00:00
End   : The last Saturday in Октябрь at 23:00:00
-----------------------
SA Eastern Standard Time
(UTC-03:00) Кайен
Ю-Ам. восточное время (лето)
-03:00:00
False
-----------------------
Montevideo Standard Time
(UTC-03:00) Монтевидео
Монтевидео (лето)
-03:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The second Sunday in Сентябрь at 02:00:00
End   : The second Sunday in Март at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The first Sunday in Октябрь at 02:00:00
End   : The second Sunday in Март at 02:00:00
-----------------------
Newfoundland Standard Time
(UTC-03:30) Ньюфаундленд
Ньюфаундлендское время (лето)
-03:30:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 00:01:00
End   : The last Sunday in Октябрь at 00:01:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Sunday in Март at 00:01:00
End   : The first Sunday in Ноябрь at 00:01:00
-----------------------
Paraguay Standard Time
(UTC-04:00) Асунсьон
Парагвай (лето)
-04:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2009 0:00:00 to 31.12.2009 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The first Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2010 0:00:00 to 31.12.2010 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2011 0:00:00 to 31.12.2011 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2012 0:00:00 to 31.12.2012 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2013 0:00:00 to 31.12.2013 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2014 0:00:00 to 31.12.2014 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2015 0:00:00 to 31.12.2015 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The first Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2016 0:00:00 to 31.12.2016 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2017 0:00:00 to 31.12.2017 0:00:00
Delta : 01:00:00
Start : The second Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2018 0:00:00 to 31.12.2018 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2019 0:00:00 to 31.12.2019 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2020 0:00:00 to 31.12.2020 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The first Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2021 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
-----------------------
Atlantic Standard Time
(UTC-04:00) Атлантическое время (Канада)
Атлантическое время (лето)
-04:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Sunday in Март at 02:00:00
End   : The first Sunday in Ноябрь at 02:00:00
-----------------------
SA Western Standard Time
(UTC-04:00) Джорджтаун, Ла-Пас, Сан-Хуан
Ю-Ам. западное время (лето)
-04:00:00
False
-----------------------
Central Brazilian Standard Time
(UTC-04:00) Манаус
Центральная Бразилия (лето)
-04:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Ноябрь at 00:00:00
End   : The second Sunday in Февраль at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The second Sunday in Октябрь at 00:00:00
End   : The last Sunday in Февраль at 00:00:00
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The third Sunday in Февраль at 00:00:00
--
Rule applies from 01.01.2009 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The third Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Февраль at 23:59:59.9990000
-----------------------
Pacific SA Standard Time
(UTC-04:00) Сантьяго
Тихоокеанское Ю-Ам. вр. (лето)
-04:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2007 0:00:00
Delta : 01:00:00
Start : The second Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2008 0:00:00 to 31.12.2008 0:00:00
Delta : 01:00:00
Start : The second Saturday in Октябрь at 23:59:59.9990000
End   : The last Saturday in Март at 23:59:59.9990000
--
Rule applies from 01.01.2009 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Saturday in Октябрь at 23:59:59.9990000
End   : The second Saturday in Март at 23:59:59.9990000
-----------------------
Venezuela Standard Time
(UTC-04:30) Каракас
Венесуэла (лето)
-04:30:00
False
-----------------------
SA Pacific Standard Time
(UTC-05:00) Богота, Кито, Лима
Ю-Ам. тихоокеанское вр. (лето)
-05:00:00
False
-----------------------
Eastern Standard Time
(UTC-05:00) Восточное время (США и Канада)
Восточное время США (лето)
-05:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Sunday in Март at 02:00:00
End   : The first Sunday in Ноябрь at 02:00:00
-----------------------
US Eastern Standard Time
(UTC-05:00) Индиана (восток)
США - восточное время (лето)
-05:00:00
False
-----------------------
Central Standard Time (Mexico)
(UTC-06:00) Гвадалахара, Мехико, Монтеррей
Центральное время Мехико (лето)
-06:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
-----------------------
Canada Central Standard Time
(UTC-06:00) Саскачеван
Центральная Канада (лето)
-06:00:00
False
-----------------------
Central America Standard Time
(UTC-06:00) Центральная Америка
Центральная Америка (лето)
-06:00:00
False
-----------------------
Central Standard Time
(UTC-06:00) Центральное время (США и Канада)
Центральное время США (лето)
-06:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Sunday in Март at 02:00:00
End   : The first Sunday in Ноябрь at 02:00:00
-----------------------
US Mountain Standard Time
(UTC-07:00) Аризона
США - горное время (лето)
-07:00:00
False
-----------------------
Mountain Standard Time
(UTC-07:00) Горное время (США и Канада)
Горное время США (лето)
-07:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Sunday in Март at 02:00:00
End   : The first Sunday in Ноябрь at 02:00:00
-----------------------
Mountain Standard Time (Mexico)
(UTC-07:00) Ла-Пас, Мазатлан, Чихуахуа
Горное время (Мексика) (лето)
-07:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
-----------------------
Pacific Standard Time
(UTC-08:00) Тихоокеанское время (США и Канада)
Тихоокеанское время США (лето)
-08:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Sunday in Март at 02:00:00
End   : The first Sunday in Ноябрь at 02:00:00
-----------------------
Pacific Standard Time (Mexico)
(UTC-08:00) Тихуана, Нижняя Калифорния
Тихоокеанская Мексика (лето)
-08:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
-----------------------
Alaskan Standard Time
(UTC-09:00) Аляска
Аляскинское время (лето)
-09:00:00
True
--
Rule applies from 01.01.0001 0:00:00 to 31.12.2006 0:00:00
Delta : 01:00:00
Start : The first Sunday in Апрель at 02:00:00
End   : The last Sunday in Октябрь at 02:00:00
--
Rule applies from 01.01.2007 0:00:00 to 31.12.9999 0:00:00
Delta : 01:00:00
Start : The second Sunday in Март at 02:00:00
End   : The first Sunday in Ноябрь at 02:00:00
-----------------------
Hawaiian Standard Time
(UTC-10:00) Гавайи
Гавайское время (лето)
-10:00:00
False
-----------------------
Samoa Standard Time
(UTC-11:00) О-в Мидуэй, Самоа
Самоанское время (лето)
-11:00:00
False
-----------------------
Dateline Standard Time
(UTC-12:00) Линия перемены дат
Линия перемены дат (лето)
-12:00:00
False
------------------------------------------------------------------


81.2. ПОДСИСТЕМА ПАМЯТИ

В этой секции мы будем заниматься подсистемой памяти.

     Память
    /      \
 Физическая   Виртуальная

- Физическая память в компьютере и ее конфигурирование
- Карта памяти
- Кэширование физической памяти
- Работа с блоками памяти
- Организация Куч
- Слабовые аллокаторы
- Оконечные языковые интерфейсы работы с памятью
- Утечки памяти и их отладка
- Виртуальная память
- Memory mapped files
- Организация виртуальной памяти в OS
- Окна памяти


81.2.1. ФИЗИЧЕСКАЯ ПАМЯТЬ

  Карта Памяти

Карта памяти на современном PC

    Conventional
    Extension ROMs (include Video BIOS)
    ROM BIOS
    Memory
    15MB holes (if any)
    Memory
    4GB holes (if any)
    Memory

  Обрезание регионов

-----------------------------
IO#/MEM	SMM	пространство
-----------------------------
X	1	SMM
0	0	I/O space
1	0	Memory
-----------------------------

  Обрезание региона по фиксированному адрессу

----------------------------------------------------
CS_ROM_MEM	CS_ROM_E000	CS_MEM  Target
----------------------------------------------------
0		X		0	нету
1		0		1	к памяти
1	        1		0	к ROM E000
----------------------------------------------------

  Обрезание региона по перемещаемому адрессу

  Настройка памяти

Откуда BIOS знает сколько установлено памяти и какие у нее характеристики?

    ранние системы
        DIP-switches
    средние системы
        модули выдают соответсвующие электрические сигналы
        о своих размерах
        схемы сводят это
        BIOS тестирует память
    современные системы
        SPD (Serial Presents detection)

  DIP-switches

IBM PC/XT
Память набита в DIP микросхемах в материнскую плату.
Объем памяти определяется переключателями, находящимися
на плате.

    SW1  SW2  SW3  SW4  SW5
64K	ON   ON   ON   ON   ON
128K    ON   OFF  ON   ON   ON
256K    ON   OFF  OFF  ON   ON
384K    ON   OFF  ON   OFF  ON
512K    ON   OFF  OFF  OFF  ON
640K    ON   OFF  ON   ON   OFF

Есть и другие значения.

  Present detection

30-pin SIMM
------------------------------------
1 	VCC 	+5 VDC
2 	/CAS 	Column Address Strobe
3 	DQ0 	Data 0
4 	A0 	Address 0
5 	A1 	Address 1
6 	DQ1 	Data 1
7 	A2 	Address 2
8 	A3 	Address 3
9 	GND 	Ground
10 	DQ2 	Data 2
11 	A4 	Address 4
12 	A5 	Address 5
13 	DQ3 	Data 3
14 	A6 	Address 6
15 	A7 	Address 7
16 	DQ4 	Data 4
17 	A8 	Address 8
18 	A9 	Address 9
19 	A10 	Address 10
20 	DQ5 	Data 5
21 	/WE 	Write Enable
22 	GND 	Ground
23 	DQ6 	Data 6
24 	A11 	Address 11
25 	DQ7 	Data 7
26 	QP 	Data Parity Out
27 	/RAS 	Row Address Strobe
28 	/CASP 	Something Parity
29 	DP 	Data Parity In
30 	VCC 	+5 VDC
------------------------------------

QP and DP = NC on non-parity modules
A9 = NC   on 256K
A10 = NC  on 256K/1M
A11 = NC  on 256K/1M/4M

72-pin SIMM
------------------------------------
pin	ECC	Normal	Description
------------------------------------
1 	VSS 	VSS 	Ground
2 	DQ0 	DQ0 	Data 0
3 	DQ1 	DQ1 	Data 1
4 	DQ2 	DQ2 	Data 2
5 	DQ3 	DQ3 	Data 3
6 	DQ4 	DQ4 	Data 4
7 	DQ5 	DQ5 	Data 5
8 	DQ6 	DQ6 	Data 6
9 	DQ7 	DQ7 	Data 7
10 	VCC 	VCC 	+5 VDC
11 	PD5 	PD5 	Presence Detect 5
12 	A0 	A0 	Address 0
13 	A1 	A1 	Address 1
14 	A2 	A2 	Address 2
15 	A3 	A3 	Address 3
16 	A4 	A4 	Address 4
17 	A5 	A5 	Address 5
18 	A6 	A6 	Address 6
19 	n/c 	n/c 	Not connected
20 	DQ8 	DQ8 	Data 8
21 	DQ9 	DQ9 	Data 9
22 	DQ10 	DQ10 	Data 10
23 	DQ11 	DQ11 	Data 11
24 	DQ12 	DQ12 	Data 12
25 	DQ13 	DQ13 	Data 13
26 	DQ14 	DQ14 	Data 14
27 	DQ15 	DQ15 	Data 15
28 	A7 	A7 	Address 7
29 	DQ16 	DQ16 	Data 16
30 	VCC 	VCC 	+5 VDC
31 	A8 	A8 	Address 8
32 	A9 	A9 	Address 9
33 	n/c 	n/c 	Not connected
34 	/RAS1 	/RAS1 	Row Address Strobe 1
35 	DQ17 	DQ17 	Data 17
36 	DQ18 	DQ18 	Data 18
37 	DQ19 	DQ19 	Data 19
38 	DQ20 	DQ20 	Data 20
39 	VSS 	VSS 	Ground
40 	/CAS0 	/CAS0 	Column Address Strobe 0
41 	A10 	A10 	Address 10
42 	A11 	A11 	Address 11
43 	/CAS1 	/CAS1 	Column Address Strobe 1
44 	/RAS0 	/RAS0 	Row Address Strobe 0
45 	/RAS1 	/RAS1 	Row Address Strobe 1
46 	DQ21 	DQ21 	Data 21
47 	/WE 	/WE 	Read/Write
48 	/ECC 	/ECC
49 	DQ22 	DQ22 	Data 22
50 	DQ23 	DQ23 	Data 23
51 	DQ24 	DQ24 	Data 24
52 	DQ25 	DQ25 	Data 25
53 	DQ26 	DQ26 	Data 26
54 	DQ27 	DQ27 	Data 27
55 	DQ28 	DQ28 	Data 28
56 	DQ29 	DQ29 	Data 29
57 	DQ30 	DQ30 	Data 30
58 	DQ31 	DQ31 	Data 31
59 	VCC 	VCC 	+5 VDC
60 	DQ32 	DQ32 	Data 32
61 	DQ33 	DQ33 	Data 33
62 	DQ34 	DQ34 	Data 34
63 	DQ35 	DQ35 	Data 35
64 	n/c 	DQ36 	Data 36
65 	n/c 	DQ37 	Data 37
66 	n/c 	DQ38 	Data 38
67 	PD1 	PD1 	Presence Detect 1
68 	PD2 	PD2 	Presence Detect 2
69 	PD3 	PD3 	Presence Detect 3
70 	PD4 	PD4 	Presence Detect 4
71 	n/c 	DQ39 	Data 39
72 	VSS 	VSS 	Ground
------------------------------------

PD2	PD1	Description
GND	GND	4/64MB
GND	NC	2/32MB
NC	GND	1/16MB
NC	NC	8MB

PD4	PD3	Description
GND	GND	50, 100 ns
GND	NC	80 ns
NC	GND	70 ns
NC	NC	60 ns

A9 = NC on 256K/512K
A10 = NC on 256K/512K/1M/4M
RAS1/RAS3 = NC on 256K/1M/4M

  Serial presents detection (SPD)

SDA     - Serial presents detect Data
SA[3:0] - Serial presents detect address
SCL     - Serial presents clock
WP	- Write protected

SPD (Serial Presents Detect)
на примере Micron DDR 256MB module

----------------------------------------------------------------
Byte	Description				Value
----------------------------------------------------------------
0	Number of bytes used in SPD		80 = 128
1	Total number of SPD bytes		08 = 256
2	Memory type				07 = DDR
3	Number of ROW addresses			12
4	Number of column adderesses		13
5	Number of banks				2
6	Module data width			72
7	Module data width (continued)		0
8	Module interface voltage level		04 = SSTL 2.5V
9	SDRAM cycle time			70
10	SDRAM access from clock			75
11	Module configuration type		02 = ECC
12	Refresh rate/type			80
13	Refresh width				08
14	Error checking SDRAM data width		08
15	Minimum clock delay random col access	01
16	Burst length supported			0E = 2,4,8
17	Number of banks on SDRAM device		04
18	CAS latencies supported			0C = 2, 2.5
19	CS latency				01 = 0
20	WE latency				02 = 1
21	SDRAM Module attributes			20
22	SDRAM Device attribute			00
23	SDRAM cycle time (CAS latency = 2)	75
24	SDRAM cycle time (CAS latency = 2)	75
25	SDRAM cycle time (CAS latency = 1)	00
26	SDRAM cycle time from CK (CAS lat = 1)	00
27	Minimum ROW precharge time		50
28	Minimum ROW active to ROW active	3C
29	Minimum RAS# to CAS# delay		50
30	Minumum RAS# pulse width		28
31	Module bank density			20  = 256K
32	Address and command setup time		A0
----------------------------------------------------------------

  Настройка адрессов модулей памяти в Chipset

Как это выглядет вутри Chipset?

На примере Intel 845PE:

----------------------------------------------------------------
For each row:	DRAM Row Boundary Register (DRBR)
        define upper boundary address of DRAM raw in 32-MB units
        DRB0 = row 0 size
        DRB1 = row 0 + row 1 size
        DRB2 = row 0 + row 1 + row 2 size
        DRB3 = row 0 + row 1 + row 2 size + row 3 size
----------------------------------------------------------------
For each row:	DRAW Row Attribute register (DRAR)
            size of page
            000 = 2K
            001 = 4K
            010 = 8K
            011 = 16K
----------------------------------------------------------------
One		DRAM Timing register
            DRAM Idle timer (how much idle DRAM cycles before precharge)
                000 = infinite
                001 = 0
                010 = 8 DRAM clock
                011 = 16 DRAM clock
                100 = 64 DRAM clock
            Activate to precharge delay (tRAS) MAX
                0   = 120 ns
                1   = reserved
            Activate to precharge delay (tRAS) MIN
                00  = 8 clocks
                01  = 7 clocks
                10  = 6 clocks
                11  = 5 clocks
            CAS# latency
                00 = 2.5 clocks
                01 = 2   clocks
                10 = 1.5 clocks
                11 = reserved
            RAS# to CAS# delay
                01 = 3 DRAM clocks
                10 = 2 DRAM clocks
            DRAM RAS# Precharge
                01 = 3 DRAM clocks
                10 = 2 DRAM clocks
----------------------------------------------------------------
One		DRAM Controller mode register
               Initialization complete
            Dynamic power-down mode enable
            Refresh mode
            Mode
            DRAM type  (example: DDR)
----------------------------------------------------------------

  Сканирование памяти

Реально смешнее - потому что надо учитывать не только количество строк
но и количество столбцов в строке которое может быть различным.

Вот что происходит если поставить неверный размер столбца:

IDEA

Собствено можно сделать тот же самый memory test
(поставив вначале минимальный размер column и постепенно его
увеличивая. Там где память станет максимального размера -
такое количество column и надо брать.

  Двухканальный режим

Понятно что для двухканального режима нам нужны модули одинакового размера,
c одинаковой организацией и одинаковыми таймингами.

Ну и естественно поддержка в chipset.

  Память и NUMA архитектуры

SMP:

Запросы к памяти симметричны для всех процессоров.
Память конфигурируется на chipset.

ccNUMA 2-node:

ccNUMA 4-node:

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

  Как происходит конфигурирование памяти?

Контроллер памяти в chipset:
    Выполняется POST в ROM-BIOS на bootstrap процессоре.
    (Имейте в виду что доступно порядка 128KB SMRAM (System Management RAM),
     которая находится внутри chipset).
    BIOS осуществляет доступ к регистрам Memory Controller Hub
    через PCI system space.

    SPD как правило подключено через SMB (System Management Bus) (физически I2C), который
    находится в ICH (I/O controller hub).

    BIOS читает SPD, подбирает совместимые параметры и программирует
    Memory controler hub.

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

    Кроме того при инициализации - надо смотреть память на каждом процессоре
    (а не только на BSP (Bootstrap processor) и cтроить общую карту памяти
    (лишняя забота для BIOS).

    Имейте в виду, что если мы не на SMP, а на ccNUMA, то скорость обращения к памяти
    зависит от того на каком процессоре находиться память.
    А эта информацию BIOS кладет в ACPI таблицы.

  Как узнать сколько памяти у BIOS?

INT 12 - BIOS - GET MEMORY SIZE
Return: AX = kilobytes of contiguous memory starting at absolute address 00000h
Note:	this call returns the contents of the word at 0040h:0013h; in PC and
      XT, this value is set from the switches on the motherboard
SeeAlso: INT 11"BIOS",INT 2F/AX=4A06h,INT 4C"Tandy 2000",MEM 0040h:0013h

C> memsize
Conventional Memory Size = 027E

Мы видем (027E) т.е. 638KB.  На самом деле ее 640KB, просто 2KB занято под дополнительный
сегмент данных BIOS.

INT 15 - SYSTEM - GET EXTENDED MEMORY SIZE (286+)
    AH = 88h
Return: CF clear if successful
        AX = number of contiguous KB starting at absolute address 100000h
    CF set on error
        AH = status
        80h invalid command (PC,PCjr)
        86h unsupported function (XT,PS30)
Notes:	TSRs which wish to allocate extended memory to themselves often hook
      this call, and return a reduced memory size.	They are then free to
      use the memory between the new and old sizes at will.
    the standard BIOS only returns memory between 1MB and 16MB; use AH=C7h
      for memory beyond 16MB
    not all BIOSes correctly return the carry flag, making this call
      unreliable unless one first checks whether it is supported through
      a mechanism other than calling the function and testing CF
    Due to applications not dealing with more than 24-bit descriptors
      (286), Windows 3.0 has problems when this function reports more
      than 15 MB. Some releases of HIMEM.SYS are therefore limited to use
      only 15 MB, even when this function reports more.
SeeAlso: AH=87h,AH=8Ah"Phoenix",AH=C7h,AX=DA88h,AX=E801h,AX=E820h

INT 15 - Phoenix BIOS v4.0 - GET BIG MEMORY SIZE
    AH = 8Ah
Return: DX:AX = extended memory size in K
SeeAlso: AH=88h,AX=E801h,AX=E820h

INT 15 - Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS
    AX = E801h
Return: CF clear if successful
        AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
        BX = extended memory above 16M, in 64K blocks
        CX = configured memory 1M to 16M, in K
        DX = configured memory above 16M, in 64K blocks
    CF set on error
Notes:	supported by the A03 level (6/14/94) and later XPS P90 BIOSes, as well
      as the Compaq Contura, 3/8/93 DESKPRO/i, and 7/26/93 LTE Lite 386 ROM
      BIOS
    supported by AMI BIOSes dated 8/23/94 or later
    on some systems, the BIOS returns AX=BX=0000h; in this case, use CX
      and DX instead of AX and BX
    this interface is used by Windows NT 3.1, OS/2 v2.11/2.20, and is
      used as a fall-back by newer versions if AX=E820h is not supported
    this function is not used by MS-DOS 6.0 HIMEM.SYS when an EISA machine
      (for example with parameter /EISA) (see also MEM F000h:FFD9h), or no
      Compaq machine was detected, or parameter /NOABOVE16 was given.
SeeAlso: AH=8Ah"Phoenix",AX=E802h,AX=E820h,AX=E881h"Phoenix"

INT 15 - newer BIOSes - GET SYSTEM MEMORY MAP
    AX = E820h
    EAX = 0000E820h
    EDX = 534D4150h ('SMAP')
    EBX = continuation value or 00000000h to start at beginning of map
    ECX = size of buffer for result, in bytes (should be >= 20 bytes)
    ES:DI -> buffer for result (see #00581)
Return: CF clear if successful
        EAX = 534D4150h ('SMAP')
        ES:DI buffer filled
        EBX = next offset from which to copy or 00000000h if all done
        ECX = actual length returned in bytes
    CF set on error
        AH = error code (86h) (see #00496 at INT 15/AH=80h)
Notes:	originally introduced with the Phoenix BIOS v4.0, this function is
      now supported by most newer BIOSes, since various versions of Windows
      call it to find out about the system memory
    a maximum of 20 bytes will be transferred at one time, even if ECX is
      higher; some BIOSes (e.g. Award Modular BIOS v4.50PG) ignore the
      value of ECX on entry, and always copy 20 bytes
    some BIOSes expect the high word of EAX to be clear on entry, i.e.
      EAX=0000E820h
    if this function is not supported, an application should fall back
      to AX=E802h, AX=E801h, and then AH=88h
    the BIOS is permitted to return a nonzero continuation value in EBX
      and indicate that the end of the list has already been reached by
      returning with CF set on the next iteration
    this function will return base memory and ISA/PCI memory contiguous
      with base memory as normal memory ranges; it will indicate
      chipset-defined address holes which are not in use and motherboard
      memory-mapped devices, and all occurrences of the system BIOS as
      reserved; standard PC address ranges will not be reported
SeeAlso: AH=C7h,AX=E801h"Phoenix",AX=E881h,MEM xxxxh:xxx0h"ACPI"

Format of Phoenix BIOS system memory map address range descriptor:
Offset	Size	Description	(Table 00580)
 00h	QWORD	base address
 08h	QWORD	length in bytes
 10h	DWORD	type of address range (see #00581)

(Table 00581)
Values for System Memory Map address type:
 01h	memory, available to OS
 02h	reserved, not available (e.g. system ROM, memory-mapped device)
 03h	ACPI Reclaim Memory (usable by OS after reading ACPI tables)
 04h	ACPI NVS Memory (OS is required to save this memory between NVS
      sessions)
 other	not defined yet -- treat as Reserved
SeeAlso: #00580

C> smap
------------------------------------------
     Address		Size	    Type
------------------------------------------
0000000000000000 000000000009F800 00000001	First 638K - available for OS
000000000009F800 0000000000000800 00000002	Extended BIOS data segment
00000000000DC000 0000000000024000 00000002	ROM BIOS and other ROMs
0000000000100000 000000001DDF0000 00000001	Memory avaiable for OS
000000001DEF0000 000000000000F000 00000003	ACPI Tables
000000001DEFF000 0000000000001000 00000004	ACPI NVS
000000001DF00000 0000000000100000 00000001      Memory available for OS
00000000FEC00000 0000000000010000 00000002	CPU and system registers
00000000FEE00000 0000000000001000 00000002	CPU and system registers
00000000FFFE0000 0000000000020000 00000002	CPU and system registers
------------------------------------------

NOTE

Имейте в виду что BIOS может не говорить о некоторых регионах памяти.
В этом случае операционная система должна считать их недоступными.

  EFI

Для получение карты памяти под EFI используется следущая функция:

EFI_STATUS  GetMemoryMap(IN OUT UINTN  * MemoryMapSize,
             IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,
             OUT UINTN * MapKey,
             OUT UINTN * DescriptorSize,
             OUT UINTN * DescriptorVersion);

    typedef struct
    {
        UINT32 	Type;				// EFI_MEMORY_TYPE
        EFI_PHYSICAL_ADDRESS 	PhysicalStart; 	// UINT64
        EFI_VIRTUAL_ADDRESS 	VirtualStart;	// UINT64
        UINT64 	NumberOfPages;
        UINT64 	Attribute;
#define EFI_MEMORY_UC 	0x0000000000000001
#define EFI_MEMORY_WC 	0x0000000000000002
#define EFI_MEMORY_WT 	0x0000000000000004
#define EFI_MEMORY_WB 	0x0000000000000008
#define EFI_MEMORY_UCE	0x0000000000000010
#define EFI_MEMORY_WP 	0x0000000000001000
#define EFI_MEMORY_RP 	0x0000000000002000
#define EFI_MEMORY_XP 	0x0000000000004000
#define EFI_MEMORY_RUNTIME 0x8000000000000000
    } EFI_MEMORY_DESCRIPTOR;

    typedef enum
    {
        EfiReservedMemoryType,
        EfiLoaderCode,
        EfiLoaderData,
        EfiBootServicesCode,
        EfiBootServicesData,
        EfiRuntimeServicesCode,
        EfiRuntimeServicesData,
        EfiConventionalMemory,
        EfiUnusableMemory,
        EfiACPIReclaimMemory,
        EfiACPIMemoryNVS,
        EfiMemoryMappedIO,
        EfiMemoryMappedIOPortSpace,
        EfiPalCode,
    } EFI_MEMORY_TYPE;

NOTE

В отличии от BIOS EFI сообщает полную карту памяти, то есть для всех регионов.


81.2.1.1. КЭШИРОВАНИЕ ФИЗИЧЕСКОЙ ПАМЯТИ

  Типы доступа к памяти по кэшированию

Структура процессора:

UC	Uncached
WC	Write-Combined
WP	Write-Protected
WT	Write-Through
WB	Write-Back

  UC (Uncached)

Кэширование не производиться. Все операции с памятью идут in-order.

  WC (Write combined)

Кэширование не производиться. Используются WC-буфера, поэтому если вы запишите
подряд два раза одну и туже память, то это запишиться в WC-буфер и когда он
будет сбрасываться то мы получим только одну запись.

Для этой зоны возможно спекулятивное чтение (когда данные читаются out-of-order)

  WT (Write Through)

Производиться аллокация строк cache в состояние S (shared), если cache miss.
Запись идет паралельно в память

  WP (Write protected)

На чтение аллокация строк cache в состояние S (shared) если cache miss.
На запись инвалидация строки cache если cache hit.
Запись идет паралельно в память.

  WB (Write back)

Запись идет в cache в состояние M (modified).

  MTRR

MTRR (Memory Type Range Registers)

    Uncached
    Write-Through
    Write-Back
    Write-combined   (store in buffer and write in burst mode)
    Write-protected

Набор MSR (Model Specific Registers) в процессоре которые управляют политикой
доступа к регионам памяти.

Это важно, так как память видеокарты мы точно не захотим кэшировать.
Кроме того это удобно для создания Shadow ROM.

Зоны которые не попадают в MTTRs идут по default memory type.

  -------------------------------------------------
MSR FEh  is MTRRcap (Memory Type Range Registers Capabilities)
    (Read-only)
    (Pentium Pro/Pentium II, Pentium 4, AMD x86-64)

    bits	description
    63..1	reserved
    10	WC	(Write combining)
    9	reserved
    8	FIX	(fixed-range registers)
    7..0	VCNT	(number of variable-range registers pairs,
             supported by processor).
  -------------------------------------------------
MSR 2FFh is MTTR Default Memory Type   (IA32_MTRR_DEF_TYPE)
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
        Bits	Description
        63..12	Reserved
        11	MTTR (Memory Type Region Registers) Enable
        10	Fixed MTRR Enable
        9..3	Reserved
        2..0	Default Memory Type
            00h - UC - uncachable
            01h - WC - write combining
            04h - WT - write throught
            05h - WP - write protect
            06h - WB - writeback
  -------------------------------------------------
MSR 200h is MTRR Physical Base 0
    (Pentium Pro/Pentium II,Pentium 4, VIA C3, AMD Athlon/Opteron)

        Bits	Descriptiron
        63..12	Physical Base
        7..0	Memory Type
  -------------------------------------------------
MSR 201h is MTRR Physical Mask 0
    (Pentium Pro/Pentium II, Pentium 4,VIA C3, AMD Athlon/Opteron)

        Bits	Descriptiron
        63..12	Physical Mask
        11	Valid
  -------------------------------------------------
MSR 202h is MTRR Physical Base 1
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 203h is MTRR Physical Mask 1
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 204h is MTRR Physical Base 2
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 205h is MTRR Physical Mask 2
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 206h is MTRR Physical Base 3
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 207h is MTRR Physical Mask 3
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 208h is MTRR Physical Base 4
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 209h is MTRR Physical Mask 4
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 20Ah is MTRR Physical Base 5
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 20Bh is MTRR Physical Mask 5
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 20Ch is MTRR Physical Base 6
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 20Dh is MTRR Physical Mask 6
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 20Eh is MTRR Physical Base 7
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 20Fh is MTRR Physical Mask 7
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 250h is MTRR Fixed 64K at 00000h   (IA32_NTRR_FIX6K_00000)
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)

  -------------------------------------------------
MSR 258h is MTRR Fixed 16K at 80000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 259h is MTRR Fixed 16K at A0000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 268h is MTRR Fixed 4K at C0000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 269h is MTRR Fixed 4K at C8000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 26Ah is MTRR Fixed 4K at D0000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 26Bh is MTRR Fixed 4K at D8000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 26Ch is MTRR Fixed 4K at E0000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 26Dh is MTRR Fixed 4K at E8000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 26Eh is MTRR Fixed 4K at F0000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------
MSR 26Fh is MTRR Fixed 4K at F8000h
    (Pentium Pro/Pentium II, Pentium 4, VIA C3, AMD Athlon/Opteron)
  -------------------------------------------------

C> mtrr
--------------------------
   MSR         Value
--------------------------
000000FE  0000000000000508	MTRR Capabilities
000002FF  0000000000000C00	MTRR Default Memory type
00000200  0000000000000006	MTRR Physical base 0
00000201  0000000FF0000800	MTRR Physical mask 0
00000202  0000000010000006	MTRR Physical base 1
00000203  0000000FF8000800	MTRR Physical mask 1
00000204  0000000018000006	MTRR Physical base 2
00000205  0000000FFC000800	MTRR Physical mask 2
00000206  000000001C000006	MTRR Physical base 3
00000207  0000000FFE000800	MTRR Physical mask 3
00000208  0000000000000000      MTRR Physical base 4
00000209  0000000000000000      MTRR Physical mask 4
0000020A  0000000000000000      MTRR Physical base 5
0000020B  0000000000000000      MTRR Physical mask 5
0000020C  0000000000000000      MTRR Physical base 6
0000020D  0000000000000000      MTRR Physical mask 6
0000020E  0000000000000000      MTRR Physical base 7
0000020F  0000000000000000	MTRR Physical mask 7
00000250  0606060606060606	MTRR Fixed 64K at 0000h
00000258  0606060606060606	MTRR Fixed 16K at 8000h
00000259  0000000000000000	MTRR Fixed 16K at A000h
00000268  0505050505050505	MTRR Fixed 4K  at C000h
00000269  0000000000000000	MTRR Fixed 4K  at C800h
0000026A  0000000000000000      MTRR Fixed 4K  at D000h
0000026B  0000000000000000	MTRR Fixed 4K  at D800h
0000026C  0000000000000000	MTRR Fixed 4K  at E000h
0000026D  0000000000000000	MTRR Fixed 4K  at E800h
0000026E  0505050505050505	MTRR Fixed 4K  at F000h
0000026F  0505050505050505	MTRR Fixed 4K  at F800h
--------------------------

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

    доступ = MIN (доступ(MTRR), доступ(page table))

--------------------------------
MTRR	PCD	PWT	Result
--------------------------------
UC	-	-	UC
--------------------------------
WC	0	-	WC
    1	0	WC
    1	1	UC
--------------------------------
WP	0	-	WP
    1	-	UC
--------------------------------
WT	0	-	WT
    1	-	UC
--------------------------------
WB	0	0	WB
    0	1	WT
    1	-	UC
--------------------------------


81.2.2. ПРИМИТИВЫ РАБОТЫ С ПАМЯТЬЮ

Основные операции работы с памятью

    Заполнение памяти шаблоном
    Копирование памяти
        с перекрыванием
        без перекрывания
    Сравнение регионов памяти
    Поиск байта в памяти

  Оптимизация примитивов работы с памятью

Собственно говоря примитивы работы с памятью используются ОЧЕНЬ ЧАСТО и поэтому они
составляют хорошую долю в общем объеме кода исполняемого в приложениях.
В реальной жизни их пишут на ассемблере, или вообще встраивают в компилятор
который порождает код на ассемблере.

Поэтому конечно все заинтересованы в том что бы эти пересылки были как можно
более быстрые.

Рассмотрим возможные варианты работы на архитектуре x86 на примере пересылки памяти:

    Варианты для x86:
        Побайтово
        Пословно
        Используя строковые команды (REP MOVS)
        Используя XMM регистры  (по 16 байт за раз)

  Побайтовая пересылка

Побайтово
    [+] самый простой вариант - мы читаем байт и пишем байт
    [-] К сожалению каждое обращение будет обращением к памяти
        Да, нам поможет cache, а если cache отсутствует то немного поможет
        Write Combining. Но все равно медленно.

    ; IN:  ESI = source addess
    ;      EDI = destination address
    ;      ECX = count

?loop:
    mov	al, [esi]
    mov	[edi],al
    inc	esi
    inc	edi
    sub	ecx, 1
    jnz	?loop

  Пословная пересылка

Пословно
    x86: максимальный размер DWORD
    x64: максимальный размер QWORD

    [+] Но по любому это будет быстрее чем байтами.
    [-] Если данные не выровнены, то на чтение/запись DWORD/QWORD будут
        тратиться по 2 обращения к памяти, если выровнены то по одному.
             Кроме того - если число пересылаемых данных не кратно 4/8,
        то надо будет копировать хвост. Или выравнивать начало.

    ; IN:  ESI = source addess
    ;      EDI = destination address
    ;      ECX = count

    mov	edx,ecx
    shr	edx, 2		; edx = edx / 4
    and	ecx, 3		; ecx = ecx % 4
?loop:	or	edx, edx
    jz	?endloop
    mov	eax, [esi]
    mov	[edi],eax
    add	esi, 4
    add	edi, 4
    dec	edx
    jmp	?loop
?endloop:
    or	ecx,ecx
    jz	?end
    mov	al,[esi]
    mov	[edi],al
    inc	esi
    inc	edi
    dec	ecx
    jmp	?endloop
?end:

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

с использованием специализированных команд процессора
    [+] Процессор знает про эти команды и специальным образом их
        оптимизирует. Могут быть передачи больше чем размерность которую
        просят (например REP MOVSD может пересылать по 8байтов за транзакцию)
    [-] Опять имеем хвосты которые надо тоже копировать
            (Да и для performance неплохо бы начало тоже добить до выравненного
         состояния)

REP   - префикс

    do
    {
        ecx -= 1;
        выполнить команду
    } while (ecx != 0)

Соответсвенно если CX = 0 и 16битная форма, то повторяется 65536 раз

MOVSB
    byte ptr es:[edi] = byte ptr ds:[esi]
    if (DF == 0)
    {
        esi += 1;
        edi += 1;
    } else {
            esi -= 1;
        edi -= 1;
    }

DF - Direction Flag (показывает в какую сторону перекрывать)
    DF = 0	увеличение адрессов
    DF = 1  уменьшение адрессов

CLD
    DF = 0

STD
    DF = 1

MOVSW
    word ptr es:[edi] = word ptr ds:[esi]
    if (DF == 0)
    {
        esi += 2;
        edi += 2;
    } else {
            esi -= 2;
        edi -= 2;
    }

MOVSD
    dword ptr es:[edi] = dword ptr ds:[esi]
    if (DF == 0)
    {
        esi += 4;
        edi += 4;
    } else {
            esi -= 4;
        edi -= 4;
    }

    ; IN:  ESI = source addess
    ;      EDI = destination address
    ;      ECX = count

    mov	edx, ecx
    shr	ecx, 2
    jz	?skip
    rep	movsd
?skip:
    and	edx, 2
    jz	?skip2
    movsw
?skip2:
    and	edx,1
    jz	?skip1
    movsb
?skip1:

    ; void* __cdecl memcpy(void* dst, const void* src, size_t count)
_memcpy:
    push	ebp
    mov	ebp,esp

    push	esi		; ABI save
    push	edi		; ABI save
    pushfd			; Save DF

    mov	edi, [ebp+8]	; dst
    mov	esi, [ebp+12]	; src
    mov	ecx, [ebp+16]	; count
    cld
    rep	movsb

    popfd			; Restore DF
    pop	edi		; ABI restore
    pop	esi		; ABI restor

    mov	eax,[ebp+8]	; return value

    mov	esp,ebp
    pop	ebp
    ret

  C использованием SSE2 команд

    SSE2 instruction set содержит команды, которые позволяют
    загружать 16-байтные XMM регистры в и из памяти.
    [+] Этот способ реально самый быстрый.
    [-] Только адресс должен быть выравнен по границе 16-байт.
        Иначе будет exception.
        Кроме того придеться тащить unaligned head & tail
        И на старых процессорах без SSE2 не проканает
        (Мало того что SSE2 есть в процессоре, OS должна его
         включить).

Вот эти инструкции:

    MOVAPS	xmm, xmm/m128
    MOVAPS	xmm/m128, xmm

  Выводы по оптимизации пересылки памяти

    Пересылка памяти
    /             \
Статической     Динамической
длинны		длинны

Статической длинны - длинна заранее известна и она константа
(Чаще всего встречается в коде порождаемом компилятором.
Компилятор знает длинну объекта и знает его выравнивание.
И он знает временные характеристики команд (когда имеет смысл использовать
команду с префиксом REP).
То же самое можно написать и ручками

; Например - объект занимает 11 байт:
    mov	esi, source_object_addr
    mov	edi, destination_object_addr
    movsd
    movsd
    movsw
    movsb

; Объект занимает 49 байт:
    mov	esi, source_object_addr
    mov	edi, destination_object_addr
    mov	ecx, 12
    rep movsd
    movsb

; Объект занимает 4 байта
    mov	eax, dword ptr [source_object_addr]
    mov	dword ptr [destination_object_addr], eax

Динамической длинны - длинна заранее не известна.
Можно либо породить код общего вида (REP MOVSD + Tail).
Либо вызвать функцию написанную на ассемблере которая будет это делать.

Критерии для работы этой функции

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

Хорошо когда выравнивание source и destination совпадают
(выравнивание в смысле по отношению к нашей возможности пересылки)

    Например:
        src  XXXXXXX1
        dst  XXXXXXX1
            выравнивания совпадают
                можем сначала передать
                    BYTE	XXXXXXXX1   Head to align
                    WORD	XXXXXXXX2
                    DWORD	XXXXXXXX4
                    DWORD	XXXXXXXX8
                    DWORD	XXXXXXXXC
                    ----------------------
                    SSE2	XXXXXXXX0   Main fast transfer
                    ....
                    SSE2	XXXXXXXX0
                    -----------------------
                    DWORD	XXXXXXXX0   Tail to size
                    DWORD	XXXXXXXX4
                    DWORD	XXXXXXXX8
                    WORD	XXXXXXXXC
                    BYTE	XXXXXXXXE

        src  XXXXXXX4
        dest XXXXXXXC
            выравнивания для 4 совпадают
                     для 16 (SSE2) уже нет
            (теоретически можно написать вариант SSE2 с
                 shuffle внутри, но пока никто не пытался.
             Это более менее терпимо когда у нас разница в
             выравнивание 8, хуже 4. Но совсем плохо при других
             выравниваниях).

Если выравнивание не совпадает, то лучший вариант REP MOSVD + Tail.

  Прочие строковые команды

SCASB/SCASW/SCASD
    SetFlags(AL  - byte ptr ES:[(E)DI])	// SCASB
    SetFlags(AX  - word ptr ES:[(E)DI])	// SCASW
    SetFlags(EAX - dword ptr ES:[(E)DI])	// SCASD
    if (DF == 0)
    {
        edi += 1;	// SCASB
        edi += 2;	// SCASW
        edi += 4;	// SCASD
    } else {
        edi -= 1;	// SCASB
        edi -= 2;	// SCASW
        edi -= 4;	// SCASD
    }

STOSB/STOSW/STOSD
    mov	byte ptr es:[(e)di], al		// STOSB
    mov	word ptr es:[(e)di], ax		// STOSW
    mov	dword ptr es:[(e)di], eax	// STOSD
    if (DF == 0)
    {
        edi += 1;	// STOSB
        edi += 2;	// STOSW
        edi += 4;	// STOSD
    } else {
        edi -= 1;	// STOSB
        edi -= 2;	// STOSW
        edi -= 4;	// STOSD
    }

CMPSB/CMPSW/CMPSD
    SetFlags(byte ptr es:[(e)di] - byte ptr ds:[(e)si])	// CMPSB
    SetFlags(word ptr es:[(e)di] - word ptr ds:[(e)si])	// CMPSW
    SetFlags(dword ptr es:[(e)di] - dword ptr ds:[(e)si])	// CMPSD
    if (DF == 0)
    {
        edi += 1;	// CMPSB
        edi += 2;	// CMPSW
        edi += 4;	// CMPSD
    } else {
        edi -= 1;	// CMPSB
        edi -= 2;	// CMPSW
        edi -= 4;	// CMPSD
    }

REPE/REPZ  - префикс

    do
    {
        ecx -= 1;
        выполнить команду
    } while (ecx != 0 && ZF == 1)

REPNE/REPNZ  - префикс

    do
    {
        ecx -= 1;
        выполнить команду
    } while (ecx != 0 && ZF == 0)

Соответсвенно:
    команда		C функция аналог
    rep movsb	memcpy/memmove
    rep stosb	memset
    rep cmpsb	memcmp
    repnz scasb	memchr/memrchr

    ; void* __cdecl memset(void* dst, int c, size_t count)
_memset:
    push	ebp
    mov	ebp,esp

    push	edi		; ABI save
    pushfd			; Save DF

    mov	edi, [ebp+8]	; dst
    mov	eax, [ebp+12]	; c
    mov	ecx, [ebp+16]	; count
    cld
    rep	stosb

    popfd			; Restore DF
    pop	edi		; ABI restore

    mov	eax,[ebp+8]	; return value

    mov	esp,ebp
    pop	ebp
    ret

    ; void* __cdecl memchr(const void* buf, int c, size_t count)
_memchr:
    push	ebp
    mov	ebp, esp

    push	edi		; ABI save
    pushfd			; Save DF

    mov	edi, [ebp+8]	; buf
    mov	eax, [ebp+12]	; c
    mov	ecx, [ebp+16]	; count

    or	edi,edi		; set ZF to 0
                ; in any case buffer must not be 0
    cld
    repnz   scasb

    or	ecx,ecx
    jnz	@1
    xor	edi, edi
@1:
    mov	eax, edi	; return value

    popfd
    pop	edi

    mov	esp,ebp
    pop	ebp
    ret

  C RTL для работы с памятью

В этой секции мы рассмотрим RTL для работы с памятью на примере
стандартной библиотеки C/C++.
Кроме того будут представлены sample implementation.
(Эти sample implementation на самом деле нереальные, а ориентированные
на понимание процесса. [например в реальных имплементациях не заводят никаких
дополнительных переменных типа char*, а просто при обновлении кастят void* в char*,
прибавляют что надо и записывают обратно в void*].

  Заполнение памяти шаблоном

void*	 memset(void* dest, int c, size_t count);
wchar_t* wmemset(wchar_t* dest, wchar_t c, size_t count);

void*	memset(void* s, int c, size_t n)
{
    char* p = (char*) s;

    assert(s != NULL)
    while(n--)
    {
        *p++ = c;
    }
    return	s;
}

  Поиск символа в памяти

void *   memchr(const void* buf, int c, size_t count);
wchar_t* wmemchr(const wchar_t* buf, wchar_t c, size_t count);

void*  	memchr(const void*  mem, int c, size_t n)
{
    char* p = (char*) mem;

    assert(mem != NULL);

    while(n--)
    {
        if ((*p) == c) return p;
        p++;
    }
    return	NULL;
}

  Копирование памяти

    Проблема: пересылка памяти - зоны могут перекрываться
    В С/C++ RTL это решается тем что мы имеем 2 функции для пересылки памяти:
        memcpy()   - без перекрывания
        memmove()  - с перекрыванием

    Как надо обрабатывать пересылку с перекрыванием
        Если ADDR(destination) < ADDR(source)
            то пересылаем от начала в конец
        Если ADDR(destination) > ADDR(source)
            то пересылаем от конца к началу
        Если ADDR(destination) == ADDR(source)
            то надо ли копировать?

Без перекрывания:

void*	memcpy(void* dest, const void* src, size_t count);
wchar_t* wmemcpy(wchar_t* dest, const wchar_t* src, size_t count);

void*   memcpy(void* restrict s1, const void* restrict s2, size_t n)
{
    char* dp = (char*) s1;
    char* sp = (char*) s2;

    assert(s1 != NULL);
    assert(s2 != NULL);

    while(n--) *dp++ = *sp++;
    return	s1;
}

С перекрыванием

void*	memmove(void* dest, const void* src, size_t count);
wchar_t* wmemmove(wchar_t* dest, const wchar_t* src, size_t count);

void*	memmove(void* s1, const void* s2, size_t n)
{
    char* dp = (char*) s1;
    char* sp = (char*) s2;

    assert(s1 != NULL);
    assert(s2 != NULL);

    if (s1 == s2) return s1;
    if (s1 <  s2)
    {
        // forward copy
        while(n--) *dp++ = *sp++;
    } else {
        // backword copy
        dp += n - 1;
        sp += n - 1;
        while(n--) *dp-- = *sp--;
    }
    return	s1;
}

Копирование до первого совпадения символа

void *	memccpy(void* dest, const void* src, int c, size_t count);

копирует до того момента пока не встретиться нужный символ или до конца.
Возвращает NULL если символ не встретился

void*	memccpy(void* s1, const void* s2, int c, size_t n)
{
    char*  dp = (char*) s1;
    char*  sp = (char*) s2;
    char   t;

    assert(s1 != NULL);
    assert(s2 != NULL);

    while(n--)
    {
        t = *sp++;
        *dp ++ = t;
        if (t == c) return dp;
    }
    return	NULL;
}

  Сравнение регионов памяти

memcmp возвращает число меньше 0 если buf1 < buf2
                   0      buf1 == buf2
            больше 0      buf1 > buf2

int	memcmp(const void* buf1, const void* buf2, size_t count);
int	memicmp(const void* buf1, const void* buf2, size_t count);

int	wmemcmp(const wchar_t* buf1, const wchar_t* buf2, size_t count);

int	memcmp(const void* s1, const void* s2, size_t n)
{
    int	t;
    char*   p1 = (char*) s1;
    char*   p2 = (char*) s2;

    assert(s1 != NULL);
    assert(s2 != NULL);

    while(n--)
    {
        if (!(t = ((*p1++) - (*p2++)))) return t;
    }
    return	0;	// memory areas is the same
}

int	memicmp(const void* s1, const void* s2, size_t n)
{
    int	t;
    char*   p1 = (char*) s1;
    char*   p2 = (char*) s2;

    assert(s1 != NULL);
    assert(s2 != NULL);

    while(n--)
    {
        if (!(t = (tolower(*p1++) - tolower(*p2++)))) return t;
    }
    return	0;	// memory areas is the same
}

int	_memicmp_l(const void* s1, const void* s2, size_t n, _locale_t locale);

  BSD варианты

Достаточно хорошо распространены в BSD мире. Glibc тоже поддерживает.

    void	bzero(void* s, size_t n);			// memset(s,0,n)
    int	bcmp(const void* s1, const void* s2, size_t n); // memcmp(s1,s2,n)
    void	bcopy(const void* s1, void* s2, size_t n);	// memcpy(s2,s1,n)
            обратите внимание у bcopy() порядок аргументов обратный по
            отношению к memcpy()

  Дополнительные RTL функции

Строго говоря в C стандарте их нет, но достаточно часто бывают в 3rd party
имплементациях, и в принципе удобно.

void*  memrchr(const void* s, int c, size_t n);
    // тоже самое, что memchr, но поиск идет от конца блока к началу

void*  mempcpy(void* dst, const void* src, size_t n);
    // тоже самое что memcpy, но возвращается указатель в блоке памяти dst,
    // указывающий на символ после последнего скопированного

void*  memmem(const void* block, size_t blksize, const void* subblk, size_t subblklen);
    // Ищет подблок в блоке памяти
    // Возвращает найденную позицию или 0, если не найдено

    // но про поиск блоков в памяти мы поговорим в секции посвященной строкам

Методы для реализации memmem можно почитать в секции
70.2.6.1.1. АЛГОРИТМЫ НА СТРОКАХ

  Secure RTL функции

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

errno_t  memcpy_s(void* dst, size_t dstsize, const void* src, size_t maxcount);
errno_t	 memmove_s(void* dst, size_t dstsize, const void* src, size_t maxcount);

---------------------------------------
dst	dstsize	   src	    return
---------------------------------------
NULL	any	   any	    EINVAL
any	any	   NULL	    EINVAL
any	= count   any	    0 (success)
---------------------------------------

errno_t memcpy_s(void * dst, size_t dstsize, const void* src, size_t maxcount)
{
    if (dst == NULL) return EINVAL;
    if (src == NULL) return EINVAL;
    if (dstsize < maxcount) return ERANGE;
    memcpy(dst, src, maxcount);
    return	0;
}

  Wide-function

Основной смысл их существования - облегчить портирование уже существовавших к тому
моментну char строковых функций к wide строкам.

// wchar.h
wchar_t*  wmemchr(const wchar_t * buf, wchar_t c, size_t count);       // C only
wchar_t*  wmemchr(wchar_t * buf, wchar_t c, size_t count);             // C++ only
const wchar_t * wmemchr(const wchar_t * buf, wchar_t c, size_t count); // C++ only

Обратите внимание на 2 функции для C++: различающиеся квалификаторами const.

// wchar.h
int 	 wmemcmp(const wchar_t * buf1, const wchar_t * buf2, size_t count);
wchar_t* wmemcpy(wchar_t *dest, const wchar_t *src, size_t count);
wchar_t* wmemmove(wchar_t *dest, const wchar_t *src, size_t count);
wchar_t* wmemset(wchar_t *dest, wchar_t c, size_t count);

errno_t  wmemcpy_s(wchar_t *dest, size_t numberOfElements, const wchar_t *src, size_t count);
errno_t  wmemmove_s(wchar_t *dest, size_t numberOfElements, const wchar_t *src, size_t count);

  Windows макросы и функции

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

// windows.h - реализовано макросами
void	FillMemory(VOID Destination, SIZE_T Length, BYTE Fill);
void    CopyMemory(PVOID Destination, const VOID* Source, SIZE_T Length);
void    MoveMemory(PVOID Destination, const VOID* Source, SIZE_T Length);
void    ZeroMemory(PVOID Destination, SIZE_T Length);

Windows Kernel Mode:

VOID
  RtlZeroMemory(
    IN VOID UNALIGNED  *Destination,
    IN SIZE_T  Length
    );

VOID
  RtlFillMemory(
    IN VOID UNALIGNED  *Destination,
    IN SIZE_T  Length,
    IN UCHAR  Fill
    );

VOID
  RtlCopyMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
    );

VOID
  RtlMoveMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
    );

SIZE_T
  RtlCompareMemory(
    IN CONST VOID  *Source1,	// интересная семантика:
    IN CONST VOID  *Source2,	// функция возвращает количество байтов от начала
    IN SIZE_T  Length		// которые совпадают
    );				// если совпадает все, то возвращается Length

LOGICAL
  RtlEqualMemory(
    CONST VOID  *Source1, 	// Возращает: TRUE если блоки памяти совпадают
    CONST VOID  *Source2, 	//            FALSE в остальных случаях
    SIZE_T  Length
    );

NOTE

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

void fast_zeromem(void * ptr, size_t size)
{
    long*	lp = (long*) ptr;
    while (size >= sizeof(long))
    {
        *lp ++ = 0;
        size -= sizeof(long);
    }
    char*   cp = (char*) lp;
    while (size-- >= 1)
    {
        *cp ++ = 0;
    }
}

  Что еще тебе надо?

На вопрос - куда же дели memrev() и где поиск шаблонов в памяти?
Собственно эти функции относяться все таки больше к массивам чем непосредственно к памяти.
Поэтому их надо смотреть в секции относящейся к массивам:  70.2.5. МАССИВЫ.


81.2.2.1. ПАРАЛЕЛЬНЫЕ АЛГОРИТМЫ НАД ПАМЯТЬЮ

THIS SECTION IS UNDER CONSTRUCTION

Понятно, что если мы работаем над достаточно малым блоком памяти, то потери на
split/join велики, но если приходиться работать над большой зоной памяти, то
паралельные алгоритмы дадут нам преймущество по скорости.

А откуда возметься такая большая зона, что бы было выгодно?
Случаи бывают разные - например обработка memory mapped files.

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

  Заполнение памяти шаблоном

Заполнение памяти шаблоном - это легко, потому что части этой операции
совершенно независимы друг от друга.

void* par_memset(void* dest, int c, size_t count)
{
    size_t   i;		// Loop counter

    char*    dp = (char*) dest;

    if (count < MINSIZE)
    {
        return memset(dest, c, count);
    }

    #pragma omp parallel for
    for (i = 0; i < count; i++)
    {
        dp[i] = c;		// обязательно массивная форма
    }

    return	dest;
}

  Копирование памяти

Рассмотрим самый простой вариант: копирование без перекрывания
Этот вариант тоже легкий - так как части операции тоже независимы
друг от друга.
Вот копирование с перекрыванием - это уже приключение.

void* par_memcpy(void* dest, const void* src, size_t count)
{
    size_t  i;	// Loop counter

    char*   sp = (char*) src;
    char*   dp = (char*) dst;

    if (count < MINSIZE)
    {
        return	memcpy(dest, src, count);
    }

    #pragma omp parallel for
    for (i = 0; i < count; i++)
    {
        dp[i] = sp[i];		// обязательно массивная форма
    }

    return	dest;
}

  Сравнение регионов памяти

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

Мы можем паралельно обработать куски памяти, но нам нужен суммарный
результат.

Дополнительная оптимизация: как только хоть в каком то куске памяти
несовпадение, то можно прекращать поиск во всех нитях.

bool  par_memcmp(const void* mem1, const void* mem2, size_t count)
{
    size_t  i;

    char*   cp1 = (char*) mem1;
    char*   cp2 = (char*) mem2;

    if (count < MINSIZE)
    {
        return	memcmp(mem1, mem2, count);
    }

    int result = 0;

    #pragma omp parallel for shared(result)
    for (i = 0; i < count; i++)
    {
        if (cp1[i] != cp2[i])
        {
            result |= 1;
            break;
        }
    }

    return !result;
}

  Поиск символа в памяти

Поиск символа в памяти - это более замороченная операция чем просто
сравнение. Потому что нам нужна самая левая позиция - где символ найден.

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

Дополнительная оптимизация которую можно сделать:
    Правильное разбиение (partitioning) задания:
        Например есть 3 нити (A,B,C).
        Можно сканировать (зоны):
            AAABBBCCC
        а можно
            ABCABCABC
        во втором случае если мы нашли то мы быстрее выйдем

    Прекращение выполнение нити, если точно есть найденное меньшее

void* par_memchr(const void* mem, int c, size_t count)
{
    size_t i;	// Loop counter
    char* cp = (char*) mem;

    void*  result;

    if (count < MINSIZE)
    {
        return	memchr(mem, c, count);
    }

    result = NULL;

    #pragma omp parallel for shared(result)
    for (i = 0; i < count; i++)
    {
        if (cp[i] == c)
        {
            #pragma omp critical
            {
                if (result == NULL)
                {
                    result = &(cp[i]);
                } else {
                     if (result < &(cp[i]))
                    {
                        result = &(cp[i]);
                    }
                }
            }
        }
    }
    return	result;
}

  Подсчет контрольной суммы

Еще одна достаточно часто встречающаяся операция - это подсчет простой
контрольной суммы. (Не CRC)

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

int	par_memchecksum(const void* mem, size_t count)
{
    size_t   i;
    char*    pc = (char*) mem;
    int	 result;

    #pragma omp parallel for reduction(+: result)	// automatically set result = 0
    for (i = 0; i < count; i++)
    {
        result += pc[i];
    }
    return	result;
}

  Прочее

Поиск подстрок мы не будем рассматривать здесь.
Хотя с точки зрения паралельности - это интересно.


81.2.3. КУЧИ: ОРГАНИЗАЦИЯ И РАБОТА

Реальная память c которой мы работаем - это кучи.
Куча - набор пулов памяти с которыми производяться локальные операции по
аллокации/деаллокации памяти.

  Операции над кучей

Операции:
    Создание кучи
    Удаление кучи
    Расширение кучи
        Добавление memory pool в кучу
    Статистика
        Размер свободного и занятого места
        Максимально возможный блок который можно выделить
    Проверка целостности кучи
    Дополнительные возможности:
        отслеживание memory leaks
    Аллокация блока памяти из кучи
        Подбор подходящего блока памяти
        Обеспечение нужного выравнивания для блока
    Освобождение блока памяти из кучи
        Объединение соседних неиспользуемых блоков
    Изменение размера уже выделенного блока памяти
    Получение информации об уже выделенном блоке памяти

  Организация кучи

Организация кучи:
    Списки
        В том числе и довольно сложные
    Bitmaps
    Метод парных меток
    Многослотовые кучи
    Slab-аллокаторы

    Для мультипоточных куч
    Структуры ориенированные на Thread Safe

  Куча односпискового типа

Пример кучи спискового типа:

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

  Блок памяти в куче

Так выглядет в общем виде типичный блок выделенный из кучи спискового типа

    Next  - указатель на следующий блок кучи
    Prev  - указатель на предидущий блок кучи
    Size  - размер блока
    Flags - флаги описывающие тип блока в куче
            Блок занят
            Блок свободен
            Блок является концом кучи
            Блок является указателем на другой memory pool

  Дырки в куче

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

Пример кучи спискового типа, содержащей дыру (Hole):

  Выделение блока в куче

malloc() - ПСЕВДОКОД

    Идем по куче пока не найдем блок который
        свободен
        и	содержит нужный размер
        Если нет такого блока обламываемся
        или запрашиваем еще памяти у системы
            если неуспешно
                обламываемся совсем
            если успешно
                добавляем эту память в нашу кучу
                пробуем снова сделать malloc()

    Если такой блок есть
        Если его длинна совпадает с запрашиваемой (с учетом slack)
            ставим флаг USED
        Делаем новый блок внутри старого
            Расчитываем его размер/указатели
            Ставим флаг FREE
        В нашем старом блоке
            Корректируем размер и указатели
            Ставим флаг Used

  Освобождение блока кучи

При освобождении блока кучи идет его объединение с смежными
свободными блоками кучи.

Как правило на 1й стадии блок объединяют с следующим (если он свободен)
А на 2й то что получилось в результате 1й стадии объединяют с предидущим/

Пример когда первая стадиня невозможна - следущий блок занят.

free() - ПСЕВДОКОД

    Первая стадия - Объединение с следующим блоком
        Если следующий блок USED
            Ставим нашему блоку FREE
        Если следующий блок FREE
            Объединяем блоки в наш блок
                Корректируем указатели
                Корректируем суммарный размер у нашего блока

    Вторая стадия - Объединение с предидущим блоком
        Если предидущий блок USED
            Все - мы закончили
        Если предидущий блок FREE
            Объединяем блоки в предидущий блок
                Корректируем указатели
                Корректируем суммарный размер у блока

Пример когда первая стадия возможна:

Пример когда первая стадия возможна:

IDEA

Оптимизация скорости аллокации

Что бы не сканировать каждый раз кучу в поисках свободных блоков (что занимает много времени),
можно держать 2 списка:
    список блоков вообще
    список свободных блоков  (кстати его указатели можно держать внутри данных самого блока)

  Куча основанная на Bitmap

Метод деления попалам - его еще называют метод близнецов.

Типовая организация: Как правило делают Bitmap для блоков кучи и работают с ним.

Как правило не используют, потому что медленная

  Куча основанная на методе парных меток

Длинна ставиться в начале и в конце блока.
Считается что если длинна отрицательна то блок занят.

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

  Многосписковая куча

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

Такой вариант любят еще называть Quick-Fit.

  Аллокатор МакКьюзика-Карелла

McKusick-Karels allocator

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

А если нет свободных блоков то выполнение пойдет через штатный malloc()

#define NDX(size)
    (size) > 128
       ? (size) > 256 : 4 : 3
        : (size) > 64
            ? 2
             : (size) > 32 : 1 : 0

#define MALLOC(space, cast, size, flags)
{
    register struct freelisthdr* flh;
    if (size <= 512 &&
        (flh = freelistaddr[NDX(size)]) != NULL)
    {
            space = (cast) flh->next;
        flh->next = * (caddr_t *) space;
    } else {
        space = (cast) malloc(size, flags);
    }
}

Пример из мира Windows - как сделать Quick-Fit кучу:

Windows поддерживает LFH кучи (Low Fragmentation Heap):

Buckets Granularity Range
1-32 	8 	    1-256
33-48 	16 	    257-512
49-64 	32 	    513-1024
65-80   64 	    1025-2048
81-96 	128 	    2049-4096
97-112 	256 	    4097-8192
113-128 512         8193-16384

Куча должна быть создана без HEAP_NO_SERIALIZABLE, и плюс к тому для
нее надо разрешить LFH:

// XP+
BOOL WINAPI HeapSetInformation(
              HANDLE HeapHandle,
              HEAP_INFORMATION_CLASS HeapInformationClass,	// HeapCompatibilityInformation
               PVOID HeapInformation,				// PDWORD = 2  LFH enable
               SIZE_T HeapInformationLength);

Кстати Windows LFH делает количество слотов в 2 раза больше чем число процессоров в системе.

  Стратегии распределения памяти

    Стратегии распределения памяти
        First Fit  (первый попавшийся блок)
        Best  Fit  (блок наиболее хорошо поподаюший под размер)
        Last  Fit  (последний попавшийся блок)
        Worst Fit  (наиболее плохо попадающий под размер блок (т.е. самый большой))
        Quick Fit  [рассматривали выше]

Проблема Best Fit - то что фрагментация слишком быстро растет.
Проблема Worst Fit - падает максимальный размер который можно выделить за раз

Списковые кучи - First Fit - в начале кучи накапливаются мелкие блоки, которые
уменьшают скорость работы кучи. С этим борются путем обхода кучи попеременно с двух
сторон, а также запоминанием позиции просмотра и выделением и освобождением блоков в нее.

  Thread-safe куча

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

Куча свободна:

Куча занята:

void* thread_safe_malloc()
{
    Lock_Heap;
    result = thread_unsafe_malloc();
    Unlock_Heap;
    return	result
}

thread_safe_free(void* p)
{
    Lock_Heap;
    thread_unsafe_free(p);
    Unlock_Heap;
}

Для локирования кучи можно использовать mutex, но как правило предпочитают
использовать критическую секцию (потому что куча интересна только внутри
процесса).

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

Куча свободна:

Куча занята на размер 16-32. Другие размеры свободно
обрабатываются.

Куча занята на 2 соседних размера (если надо разложить больший блок
на меньшие, или наоборот собрать).

  Поддержка MT-версий со стороны заголовочных файлов:

void* _st_malloc(size_t size);	// Single thread, faster, but not MT-safe
void* _mt_malloc(size_t size);	// Multi-thread safe, slower, but safe

#ifdef	_MT_
#define	malloc	_mt_malloc
#else
#define	malloc	_st_malloc
#endif

  Пример организации кучи:

Классическая организация кучи UNIX приложения.
(Исходники взяты из K&R 2ed):
(Дополнительная память аллокируется через sbrk()).

------------------------------------------------------------
typedef long Align;

union header
{
    struct
    {
        union header*  ptr;
        unsigned       size;
    } s;
    Align x;
};

typedef union header Header;

static Header  base;		// Empty list to get started
static Header* freep = NULL;	// Start of free list

Header* morecore(unsigned);

void * malloc(unsigned nbytes)
{
    Header *p, *prevp;
    unsigned	nunits;

    nunits = (nbytes + sizeof(Header) - 1);
    if ((prevp = freep) == NULL)	// No free list yet
    {
        base.s.ptr = freeptr = prevptr = &base;
        base.s.size = 0;
    }

    for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr)
    {
        if (p->s.size >= nunits)	// big enough
        {
            if (p->s.size == nunits)	// exactly
            {
                prevp->s.ptr = p->s.ptr;
            } else {
                // allocate tail end
                p->s.size -= nunits;
                p+= p->s.size;
                p->s.size = nunits;
            }
            freep = prevp;
            return (void*) (p + 1);
        }
            if (p == freep)		// wrapped around free list
        {
            if ((p = morecore(nunits)) == NULL) return NULL; // none left
        }
    }
}

#define	NALLOC	1024

static Header *morecore(unsigned nu)
{
    char*  cp, *sbrk(int);
    Header* up;

    if (nu < NALLOC) nu = NALLOC;

    cp = sbrk(nu * sizeof(Header));
    if (cp == (char*) -1)		// no space at all
    {
        return	NULL;
    }
    up = (Header*)  cp;
    up -> s.size =  nu;
    free((void*) (up+1));
    return	freep;
}

void free(void* ap)
{
    Header*  bp, *p;

    bp = (Header*) ap-1;

    for (p = freep;  !(bp > p &&  bp < p->s.ptr); p = p->s.ptr)
    {
        if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)
            break;
    }

    if (bp + bp->size == ptr->s.ptr)	// Join to upper nbr
    {
        bp->s.size += p->s.ptr->s.size;
        bp->s.ptr  = p->s.ptr->s.ptr;
    } else {
        bp->s.ptr  = p->s.ptr;
    }

    if (p + p->size == bp)			// Join to lower nbr
    {
        p->s.size +=  bp->s.size;
        p->s.ptr  =  bp->s.ptr;
    } else {
        p->s.ptr = bp;
    }
    freep = p;
}
------------------------------------------------------------

  Типовые RTL для кучи на примере Windows

  Управление кучей

 Windows

HANDLE WINAPI HeapCreate(
               DWORD flOptions,
               SIZE_T dwInitialSize,
                SIZE_T dwMaximumSize);

    // flOptions:
    //	HEAP_CREATE_ENABLE_EXECUTE
    //	HEAP_GENERATE_EXCEPTIONS	// если ошибка в аллокации
    //	HEAP_NO_SERIALIZE

BOOL WINAPI HeapDestroy(HANDLE hHeap);

SIZE_T WINAPI HeapCompact(HANDLE hHeap,		// decommiting large free blocks of memory
                    DWORD dwFlags);

    // dwFlags:
    //	HEAP_NO_SERIALIZE

BOOL WINAPI HeapValidate(HANDLE hHeap,
               DWORD dwFlags,
              LPCVOID lpMem);

    // dwFlags:
    //	HEAP_NO_SERIALIZE

BOOL WINAPI HeapLock(HANDLE hHeap);

BOOL WINAPI HeapUnlock(HANDLE hHeap);

HANDLE WINAPI GetProcessHeap(void);

DWORD WINAPI GetProcessHeaps(
  __in          DWORD NumberOfHeaps,
  __out         PHANDLE ProcessHeaps
);

  Использование кучи

 Windows

LPVOID WINAPI HeapAlloc(HANDLE hHeap,
            DWORD dwFlags,
            SIZE_T dwBytes);
    // dwFlags:
    //	HEAP_GENERATE_EXCEPTIONS
    //	HEAP_NO_SERIALIZE
    //	HEAP_ZERO_MEMORY

BOOL WINAPI HeapFree(HANDLE hHeap,
                  DWORD dwFlags,
               LPVOID lpMem);

    // dwFlags:
    //	HEAP_NO_SERIALIZE

LPVOID WINAPI HeapReAlloc(HANDLE hHeap,
               DWORD dwFlags,
                LPVOID lpMem,
               SIZE_T dwBytes);

    // dwFlags:
    //	HEAP_GENERATE_EXCEPTIONS
    //	HEAP_NO_SERIALIZE
    //	HEAP_REALLOC_IN_PLACE_ONLY
    //	HEAP_ZERO_MEMORY		// естественно для additional region

SIZE_T WINAPI HeapSize(HANDLE hHeap,		// Return size of block
                 DWORD dwFlags,
                LPCVOID lpMem);		// блок памяти

    // dwFlags:
    //	HEAP_NO_SERIALIZE

  Просмотр кучи

 Windows

BOOL WINAPI HeapWalk(HANDLE hHeap,
               LPPROCESS_HEAP_ENTRY lpEntry);

    typedef struct _PROCESS_HEAP_ENTRY
    {
        PVOID lpData;
        DWORD cbData;
        BYTE cbOverhead;
        BYTE iRegionIndex;
        WORD wFlags;
        union
        {
            struct
            {
                HANDLE hMem;
                DWORD dwReserved[3];
            } Block;

            struct {
                DWORD dwCommittedSize;
                DWORD dwUnCommittedSize;
                LPVOID lpFirstBlock;
                LPVOID lpLastBlock;
            } Region;
        };
    } PROCESS_HEAP_ENTRY,  *LPPROCESS_HEAP_ENTRY;

  Откуда беруться начальные настройки для кучи процесса в Windows?

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

--------------------------------------------------------------------------------
- - - - - - - PE Executable - - - - -
00000080 : dump  (0004)  Signature
00000080 :  50 45 00 00                                      [PE..------------]
00000084 : word      014C Target CPU
            * Intel i386
00000086 : word      0004 Number of Sections
00000088 : dword 3546A016 Time/Date Stamp
0000008C : dword 00000000 Pointer to Symbol Table
00000090 : dword 00000000 Number of Symbols
00000094 : word      00E0 Size of Optional Header
00000096 : word      010F Characteristics
           [01] * File not contain relocations
           [02] * This is executable file, not OBJ/LIB
00000098 : word      010B Magic
            * Normal Executable
0000009A : byte        05 Major Link Version
0000009B : byte        00 Minor Link Version
0000009C : dword 0000A800 Size of Code
000000A0 : dword 00005C00 Size of Initialized data
000000A4 : dword 00000000 Size of Uninitialized data
000000A8 : dword 000043A0 RVA of Entry Point
000000AC : dword 00001000 RVA of Base of Code
000000B0 : dword 0000C000 RVA of Base of Data
000000B4 : dword 00400000 Image Base
000000B8 : dword 00001000 Segment Aligment
000000BC : dword 00001000 File Aligment
000000C0 : word      0004 Major OS Number
000000C2 : word      0000 Minor OS Number
000000C4 : word      0000 Major Image Version
000000C6 : word      0000 Minor Image Version
000000C8 : word      0004 Major Subsystem Version
000000CA : word      0000 Minor Subsystem Version
000000CC : dword 00000000 Reserved
000000D0 : dword 00013000 Size of Image
000000D4 : dword 00000400 Size of Headers
000000D8 : dword 00020D79 Checksum
000000DC : word      0002 Subsystem
            * Windows GUI
000000DE : word      0000 DLL Characteristics = 0
000000E0 : dword 00100000 Size of Stack Reserve
000000E4 : dword 00001000 Size of Stack Commit
000000E8 : dword 00100000 Size of Heap Reserve		<============
000000EC : dword 00001000 Size of Heap Commit	        <============
000000F0 : dword 00000000 Loader Flag = 0
000000F4 : dword 00000010 Number of RVA and Sizes
--------------------------------------------------------------------------------

А в заголовок они попадают из DEF файла, если он есть. А если нет то ставяться по
умолчанию.

---------------------------
    HEAPSIZE	1024
    STACKSIZE	4096
---------------------------

Еще одна возможность ключики линкера:

/HEAP:RESERVE[,COMMIT]


81.2.3.1. СЛАБОВЫЕ АЛЛОКАТОРЫ

  Slabовые кучи

Slab (плитка) кучи - предназначены для быстрого выделения объектов одинакового размера.
Как правило используются внутри операционной системы (например чтобы хранить inode
структуры).

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

Меньше затрат на доп. информацию - так как размер блока не нужно хранить в блоке.

Принцип работы:
    Есть страницы
    Страница может быть
        Full	(полностью занята)
        Partial (частично свободна)
        Free (полностью свободна).

    Если есть место в Partial страницах - то береться из них
    Если нет то береться из Free страницы
    Если нет и там - просим систему дать еще памяти, заводим Free страницу и
    осуществляем аллокацию из нее.

    Если у нас есть Free страницы и система просит их отдать - отдаем без проблем.

Распределение внутри слабовой страницы как правило делается с помощью списка
свобных блоков.
    Аллокация - берем первый, обновляем список свободных
    Деаллокация - пишем в блок указатель на текущий первый
              пишем указатель на блок в указатель на текущий первый

На первый же запрос мы отдадим того кто последний использовался, он наверняка еще
в процессорном cache - будет еще быстрее работать.

Можно иметь разные страницы для разных процессоров.
И конечно слабовый аллокатор защищается от multi-thread, причем это может быть
на уровне страницы.

Другая особенность slab-аллокатора, то что он предоставляет (optional) интерфейсы
типа конструктора и деструктора, которые будут вызываться при создании и
освобождении объектов.

Пример Linux Kernel slab-cache:

kmem_cache_t* kmem_cache_create(const char* name,
                size_t      size,
                    size_t      offset,
                unsigned long flags,
                void (*ctor)(void*,kmem_cache_t*,unsigned long),
                void (*dtor)(void*,kmem_cache_t*,unsigned long));

        // flags is:
        //	SLAB_NO_REAP
        //	SLAB_HWCACHE_ALIGN
        //	SLAB_MUST_HWCACHE_ALIGN
        //	SLAB_POISON		fill by pattern A5
        //	SLAB_RED_ZONE		for detect buffer oveflow
        //	SLAB_PANIC              panic if can't allocate
        //	SLAB_CACHE_DMA

int	kmem_cache_destroy(kmem_cache_t* cachep);

void*   kmem_cache_alloc(kmem_cache_t* cachep, int flags);
void	kmem_cache_free(kmem_cache_t* cachep, void* objp);

Такие же структуры есть и в Windows Kernel
Для Paged и Non-Paged памяти:

VOID
  ExInitializePagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside,
    IN PALLOCATE_FUNCTION  Allocate  OPTIONAL,
    IN PFREE_FUNCTION  Free  OPTIONAL,
    IN ULONG  Flags,
    IN SIZE_T  Size,
    IN ULONG  Tag,
    IN USHORT  Depth	// reserved, must be 0
    );

// PALLOCATE_FUNCTION is:
PVOID
XxxAllocate (
    IN POOL_TYPE PoolType,            // PagedPool
    IN SIZE_T  NumberOfBytes,          // value of Size
    IN ULONG  Tag                     // value of Tag
    );

// PFREE_FUNCTION is:
VOID
XxxFree (
    PVOID  Buffer
    );

PVOID
  ExAllocateFromPagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside
    );

VOID
  ExFreeToPagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside,
    IN PVOID  Entry
    );

VOID
  ExDeletePagedLookasideList(
    IN PPAGED_LOOKASIDE_LIST  Lookaside
    );

VOID
  ExInitializeNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside,
    IN PALLOCATE_FUNCTION  Allocate  OPTIONAL,
    IN PFREE_FUNCTION  Free  OPTIONAL,
    IN ULONG  Flags,
    IN SIZE_T  Size,
    IN ULONG  Tag,
    IN USHORT  Depth
    );

PVOID
  ExAllocateFromNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside
    );

VOID
  ExFreeToNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside,
    IN PVOID  Entry
    );

VOID
  ExDeleteNPagedLookasideList(
    IN PNPAGED_LOOKASIDE_LIST  Lookaside
    );

  Slab-аллокаторы и архитектура cache

Из обычных аллокаторов выделяют разнородные объекты, из слабовых
выделяют однородные. Есть ньюансы связанные с кэшированием:

Отметим, что типовой cache является set-associative:

Возьмем типовой L1 data cache:

    L1 data: 16K, 4 way, 32 byte per line

всего может быть Lines:

    LINE = CACHE_SIZE / BYTE_PER_LINE / WAYS

для нашего примера:

    LINE = 16K / 32 / 4 = 128

Что мы имеем по адрессу:
    3..0	byte index
       10..4	LINE
       31..11	TAG

Что означает, что через каждые 4K данные будут ложится в одну и туже line,
а при этом количество ways ограничено.

Поскольку slab-аллокатор выдает объекты одинакового размера, хорошо
бы что бы они ложились в разные lines cache.

(Учитывая что у объектов как правило есть поля списков, к которым
обращения происходят чаще всего).

Такие ситуации возникают если размер объекта с учетом выравниваний кратен
степени двойки.

Предположим что объект имеет размер 512 байт и поле списков находится
прямо в начале объекта.

Тогда имеем при выделении подряд:

    index	Cache_LINE	index Cache_LINE
    0	0		8	0
    1	16		9	16
    2	32		10	32
    3	48		11	48
    4	64		12	64
    5	80		13	80
    6	96		14	96
    7	112 		15	112

Достаточно иметь список из 32 объектов, что бы при прохождение по этому списку
мы гарантированно выбивали строку из 4-ways cache с организацией описанной
выше.

то есть мы увидим падение производительности из за того что часто использованные
поля объекта ложатся в одинаковые линии cache.

Поэтому правильный слабовый аллокатор должен понимать такие вещи и смещать
расположения объектов на некоторых своих страницах.


81.2.3.2. ОКОНЕЧНЫЕ ЯЗЫКОВЫЕ ИНТЕРФЕЙСЫ РАБОТЫ С ПАМЯТЬЮ

  Оконечные интерфейсы работы с памятью

  C RTL

void *malloc(size_t size);

void free(void *memblock);

void *calloc(size_t num, size_t size);	// and zero memory

void * calloc(size_t numel, size_t elsize)
{
    size_t  msize = numel * elsize;		// Unsafe

    assert(msize != 0);

    void * p = malloc(msize);
    if (!p) return p;
    return	memset(p,0,msize);
}

void *realloc(void * ptr, size_t size);

realloc
    PTR	size
    0	x	malloc
    x	0	free
    x	y	realloc
if no memory, then no realloc action and return 0.

realloc - очень опасная функция.
Если вы меняете размер блока памяти (даже в сторону уменьшения) у Вас нет
гарантии того, что блок остался на месте.

Семантика изменения размера:
    Если есть возможность изменить размер in-place
        Делаем in-place
    Если нет
        Аллокируем блок памяти нового размера
            Копируем туда исходный блок памяти
                Если новый меньше то только часть
                Если новый больше в остатке будет мусор.
            Удаляем исходный блок памяти

Единственное что гарантируется стандартом C, это то что если realloc не может изменить
размер блока, то он вернет NULL, а блок не удалит.

// Версия не делающая in-place изменение размера, но имеющая все
// пороки свойственный realloc
void* realloc(void* ptr, size_t size)
{
    void*   nbp;	  // new block pointer
    size_t  oldsize;  // old block size
    size_t  cpysize;  // copy size

    if (size == 0)
    {
        if (ptr == NULL) return NULL;
        free(ptr);
        return	NULL;
    }

    // size != 0
    if (ptr == NULL)
    {
        return	malloc(size);
    }

    nbp = malloc(size);
    if (nbp == NULL) return NULL;

    oldsize = _msize(ptr);	// не стандартная функция возвращающая размер
                // блока в куче

    cpysize = (size < oldsize)? size : oldsize;

    memcpy(nbp, ptr, cpysize);
    free(ptr);
    return	nbp;
}

Всегда проверяйте значения которые вернул malloc/realloc (даже на уменьшении)

    if (!(p = malloc(size)))
    {
        // Process error
    }

Проверяйте на NULL значения которые собираетесь отдать free

    if (p) free(p);

Используйте sizeof() для структур

    struct A*  h;
    h = malloc(arraycount * sizeof(*h));

Что мы хотим:

    Возвращение размера блока в куче
    realloc, который не будет удалять оригинал, а делать все in-place

  C++ RTL

void* __cdecl operator new(size_t count) throw(std::bad_alloc);
void* __cdecl operator new(size_t count, const std::nothrow_t&) throw();
void* __cdecl operator new(size_t count, void* object) throw();

void* __cdecl operator new[](size_t count) throw(std::bad_alloc);
void* __cdecl operator new[](size_t count, const std::nothrow_t&) throw();
void* __cdecl operator new[](size_t count, void* object) throw();

void __cdecl operator delete(void * object) throw(std::bad_alloc);
void __cdecl operator delete(void * object,  const std::nothrow_t&) throw();
void __cdecl operator delete(void * object, void * memory) throw();

void __cdecl operator delete[](void * object) throw(std::bad_alloc);
void __cdecl operator delete[](void * object,  const std::nothrow_t&) throw();
void __cdecl operator delete[](void * object, void * memory) throw();

void* operator new(std:size_t size) throw(std::bad_alloc)	// Standard
{
    void* ptr = std::malloc(size);
    if (ptr == 0)

        throw std::bad_alloc();
    return ptr;
}

void * operator new(size_t, void* p)	// Placement
{
    return	p;
}

void* operator new (size_t size, const std::nothrow_t& dummy) 	// Now throw
{
        if (size == 0) size = 1;
        void* last_alloc;
        while (!(last_alloc = malloc(size)))
        {
            if (_new_handler)
                (* _new_handler)();
            else return 0;
        }
        return last_alloc;
}

void* operator new[](std::size_t size) throw(std::bad_alloc)
{
    return	operator new(size);
}

void operator delete(void* ptr)
{
    if (ptr) free(ptr);
}

typedef void (*new_handler)();
new_handler set_new_handler(new_handler new_p)throw()

// Visual C++
_PNH _set_new_handler( _PNH pNewHandler);
int  _set_new_mode( int newhandlermode );

  операторы new и delete

Различайте операторы new/delete и функции:

    new A(params)
    //	A* this = operator new(sizeof(A));
    //	A::A(A* this, params)

    delete a;
    //	if (a != 0)
    //	{
    //		A::~A(A* a);
    //		operator delete(a);
    //	}

Почему нельзя делать mixed new/free, malloc/delete?
Самое опасное это new[]/delete[] для не POD типов.
Что бы вызвать нужное число деструкторов компилятор как правло записывает
в память перед первым элементом их число.

    new A[count]
    //	size_t*  mem = operator new(sizeof(A) * count + sizeof(size_t));
    //	* mem = count;
    //	A*       arr = (A*) ++mem;
    //	for (int i = 0; i < count; i++)
    //	{
    //		A* this = &(arr[i]);
    //		A::A(A* this);
    //	}

    delete [] a;
    //	size_t*  mem = (size_t*) a;
    //	size_t   count = *(--mem);
    //	for (int i = 0; i < count; i++)
    //	{
    //		A* this = &(a[count-i-1]);
    //		A::~A(A* this);
    //	}
    //	operator delete(mem);

  Пользовательские операторы new/delete

Windows NT Kernel Mode:

PVOID   ExAllocatePool(IN POOL_TYPE  PoolType,
                   IN SIZE_T  NumberOfBytes);

    // POOL_TYPE is
    //	NonPagedPool
    //	PagedPool
    //	NonPagedPoolMustSucceed
    //	NonPagedPoolCacheAligned
    //	PagedPoolCacheAligned
    //

VOID	ExFreePool(IN PVOID p);

PVOID	ExAllocatePoolWithQuota(				// Аллокированная память идет
            IN	POOL_TYPE	PoolType,	// в квоту текущего процесса
            IN	ULONG		NumberOfBytes);

inline void* __cdecl operator new(unsigned int nSize, POOL_TYPE iType)
{
    return	ExAllocatePool(iType,nSize);
}

char* pch = new (PagedPool) char[BUF_SIZE];
сhar* npp = new (NonPagedPool) char[BUF_SIZE];

  Статистика

Иногда хочеться статистики. Статистика на входит в стандартную библиотеку C/C++.
Это всегда 3rd party расширения, зависящие от среды.

1) Размер блока памяти в куче

size_t  _msize(void* memblock);		// Visual C++

2) Для физических targets нам важно знать размер пространства которое еще осталось
   и кроме того размер самого большого блока который мы можем аллокировать.

unsigned long farcoreleft(void);	// Borland C++ 3.1 DOS

  Выделение выровненной памяти

Выделение выровненного буфера.

Иногда требуется:
    Некоторые данные должны быть выровнены
        SSE типы данных
        Некоторые типы буферов

    Кроме того выравненность имеет свои плюсы например с точки зрения
    cache и подсистемы ввода/вывода.

// stdlib.h  4.4BSD

void * memalign(size_t blocksize, size_t align)		// Wrapper accross malloc

Соответсвенно сильно зависит от среды могут ли такие блоки освобождаться
через free(). GNU C/C++ library support it. BSD нет.
РЕАЛИЗАЦИЯ СВОЕЙ КУЧИ ДОЛЖНА ПОЗВОЛЯТЬ ДЕЛАТЬ ALIGNED ALLOCATION.

int   posix_memalign(void** memptr, size_t align, size_t size);

Еще один вариант, только POSIX.

Как реализовать самим:
    запрашиваем размер = размер + (align-1)
    выравниваем указатель на границу (ptr &= ~(align-1))

только такое не осободишь с помощью free(), поэтому для овобождение надо кушать больше
памяти и хранить дополнительно указатель. Поэтому имплементация получается более сложная.

// нет проверок и обрезаний на степень 2 для выравнивания

void*  aligned_malloc(size_t size, size_t align)
{
    if (align < sizeof(void*)) align = sizeof(void*);
    char*   p  = (char*) malloc(size + align + sizeof(void*) - 1);
    size_t  al = ((intptr_t) p) % align;
    char*   ap;
    void**  sp;

    if (al == 0)
    {
        ap = p + align;
    } else if (al > (align - sizeof(void*)))
    {
        ap = p + (align - al) + align;
    } else {
        // we have enough space
        ap = p + align - al;
    }
    sp = (void**) (ap - sizeof(void*));
    *sp = p;
    return	ap;
}

void   aligned_free(void* alignedp)
{
    char*   p = (char*) alignedp;
    void** rp = (void**) (p - sizeof(void*));
    free(*rp);
}

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

Еще один часто встречающайся вариант - аллокация по границе страницы.

void * valloc(size_t size)
{
    returm memalign(getpagesize(), size);
}

  Некоторые дополнительные полезные примитивы

//libpub
void *memdup(const void *, size_t);	// Аллокировать heap и скопировать в него
                    // содержимое блока памяти

void* memdup(const void* blk, size_t size)
{
    void* tblk = malloc(size);
    if (tblk == NULL) return NULL;
    memcpy(tblk, blk, size);
    return	tblk;
}

  Маркирование кучи

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

Кстати под Windows маркирование удобно делать следущим образом:
делаем HeapCreate(), потом работаем с кучей, потом ее убиваем.

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

  Выделение памяти из стека

Это возможно далеко не на каждой платформе

void* alloca(size_t size);

; Sample stupied implementation of alloca()
; DOS 16-bit NEAR __cdecl
; No checks for stack overflow

_alloca:
    pop	bx	; Return address
    pop	ax	; Number of bytes to allocate

    add	ax, 1
    and	ax, 0fffeh	; Align to WORD

    sub	sp, ax
    push	ax	; Parameter, which will cleared
            ; by caller, 'cos __cdecl
    jmp	bx

  Пример реализации Default кучи в Win32

CODE

void* malloc(size_t size)
{
    return	HeapAlloc(GetProcessHeap(), 0, size);
}

void* calloc(size_t numel, size_t elsize)
{
    return  HeapAlloc(GetProcessHeap(),
              HEAP_ZERO_MEMORY,
              numel * elsize);
}

void  free(void* p)
{
    HeapFree(GetProcessHeap(), 0, p);
}

void* realloc(void* p, size_t size)
{
    if (!size)
    {
        if (p) free(p);
        return	NULL;
    }
    if (!p) return malloc(p);

    return HeapReAlloc(GetProcessHeap(), 0, (LPVOID) p, (SIZE_T) size);

}

size_t _msize(void* p)
{
    return HeapSize(GetProcessHeap(), 0, p);
}


81.2.3.2.1. БОРЬБА С УТЕЧКАМИ ПАМЯТИ

  Отслеживание

Борьба с ошибками и утечками памяти

Ошибки:
    Доступ к уже особожденной памяти
    Освобождение одного указателя дважды
    Передача для освобождения указателя не из кучи
    Выход за пределы буфера
    Не освобождение памяти (memory leaks).

Отладка утечек
    Debug Version of MSVC RTL расписывает кучу паттернами.
        CDh	выделена    malloc/new
        DDh	освобождена free/delete
        FDh	используется для барьеров
        ABh	выделена LocalAlloc
        CCh	иногда неинициализированные переменные /GZ

    Как правило выделяется больше памяти чем запрашивали и некоторая
    зона до возвращаемого блока и некоторая зона после заполняется
    паттернами. А так же делают invalid pages до и после

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

_DEBUG

Проброс дополнительной метаинформации о памяти:

Visual C++ RTL:
    имя файла и строка где было выделение.

void *_malloc_dbg(size_t size,
             int blockType,
                  const char *filename,
                  int linenumber);

blockType - определяет тип аллокации. Для пользователя и для RTL он различный
(считается что в RTL нет leaks).

#ifdef	_DEBUG
#define	malloc(x)	_malloc_dbg(x, _CLIENT_BLOCK, __FILE__, __LINE__)
#endif

В принципе имея метанинформацию можно сделать отчет о том, какие блоки не были
освобождены.

  Языковая поддержка

В С++ мы имеем языковую поддержку

    Объект
        Конструктор
        Деструктор

Когда объект выходит из scope, то у него вызывается деструктор.

    {
        A	a;

    }	// неявно вызывается деструктор A::~A(&a)

Это удобно и работает для объектов класса auto.
Но что делать когда объект находится в динамической памяти (то есть распределен из кучи).

    {
        A*	a = new A;

    }	// указатель остался висящим - никто его не удалил

  auto_ptr

STL содержит шаблон auto_ptr<> который позволяет держать указатель в единственном числе.
(К сожалению нельзя использовать в контейнерах)

Созданный auto_ptr указывает на данные

Копирование auto_ptr (до):

Копирование auto_ptr (после):

Освобождение нулевого auto_ptr:

Освобождение ненулевого auto_ptr (часть 1):

Освобождение ненулевого auto_ptr (часть 2):

template <class T> class auto_ptr
{
public:
    T*  ref;

    // основной конструктор
    explicit auto_ptr(T* p = 0) : ref(p) { }

    // копирующий конструктор
    auto_ptr(auto_ptr<T>& r)  : ref(r.release()) { }

    T* release()
    {
        T*  temp = ref;
        ref = NULL;
        return	temp;
    }

    void reset(T* p)
    {
        if (p != ref) delete ref;
        ref = p;
    }

    ~auto_ptr()
    {
        delete ref;	// это безопасно
    }

    auto_ptr<T>& operator=(auto_ptr<T>& r)
    {
        reset(r.release());
        return *this;
    }

    // отпущены все ухищрения необходимые для того что бы
    // к auto_ptr можно было обращаться как к T*

};

  Smart pointers

А что делать если нам указатель нужен в множестве экземпляров?
Один из путей решения - делаем связку из двух объектов:

    locus_ptr
        содержащего искомый указатель и счетчик ссылок

    weak_ptr
        ссылающийся на locus_ptr

Если заводим новый weak_ptr, счетчик ссылок в locus_ptr обновляется.

При удаление счетчик ссылок уменьшается, если он достигает 0, То locus_ptr
убивает себя.

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

template <class T> class weak_ptr;

template <class T> class locus_ptr
{
friend class weak_ptr<T>;

private:
     T*	ref;
volatile int	count;

    explicit locus_ptr<T>(T* p) : ref(p), count(1) { }

    ~locus_ptr<T>()
    {
        delete ref;
    }

    void	aquire()
    {
        ++count;
    }

    void	release()
    {
        --count;
        if (count == 0)
        {
            delete this;
        }
    }
};

template <class T> class weak_ptr
{
    locus_ptr<T>* ip;

public:
    weak_ptr<T>() : ip(0) { }

    explicit weak_ptr<T>(T* p)
    {
        ip = new locus_ptr<T>(p);
    }

    weak_ptr<T>(weak_ptr<T>& x)		// copy constructor
    {
        if (x.ip) x.ip->aquire();
        ip = x.ip;
    }

    ~weak_ptr<T>()
    {
        if (ip)	ip->release();
    }

    weak_ptr<T>& operator=(weak_ptr<T>& x)	// assignment operator
    {
        if (ip != x.ip)
        {
            if (x.ip) x.ip->aquire();
            if (ip)   ip->release();
            ip = x.ip;
        }
        return(*this);
    }

    T* operator->()
    {
        if (ip)	return ip->ref;
        return	0;
    }

    T& operator*()
    {
        return *(ip->ref);
    }

    int count()
    {
        if (ip) return	ip->count;
        return	0;
    }

    operator bool()
    {
        return ip != 0;
    }
};

Могут быть еще более сложные структуры, которые отслеживают все ссылки и если
надо удалить объект, то обновляют их.

Можно сделать структуры которые следят за рсаположением объекта в памяти, и если
объект перемещается, то обновляют себя.

В общем огромное поле деятельности для программистов, ограниченное в основном
фантазией и уровнем того,

Shared ptr структуры есть в Boost:
Шаблоны
    shared_ptr
    weak_ptr
кстати это вошло в С++ TR1 (добавление к C++ стандарту).


81.2.4. ПАМЯТЬ С ТОЧКИ ЗРЕНИЯ ПРИЛОЖЕНИЙ

У нас существуют 3 основные типа использования памяти в приложениях в современных операционных
системах:

    Физическая память
    Виртуальная сегментная память
    Виртуальная страничная память

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

  Физическая память

Память которая физически присутсвует
    Свойства:
        всегда присутсвует по тем же самым адрессам

Собственно так операционные системы строют свои структуры памяти.

    Мы запросили BIOS - он нам сказал какие регионы памяти доступны
    для использования. Их мы и засовываем в наш pool.

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

На примере DOS:
(Мы берем сейчас только главную часть без UMB)

 MS-DOS

----------------------------------------------------------
allocate conventional memory block 48h [DOS]
    INT21h/Fn48h		DOS 2+

In:	AX = 48h
    BX = number of paragraphs (16-bytes)
Out:	if CF = 0 success
        AX = segment of memory
    if CF =1 error
        AX = error code
        BX = max available block (in paragraphs)
----------------------------------------------------------
free conventional memory block 49h [DOS]
    INT21h/Fn49h		DOS 2+

In:	AX = 49h
    ES = segment of block for free
Out:	if CF = 0 success
    if CF = 1 error
        AX = error code
----------------------------------------------------------
reallocate conventional memory block 4Ah [DOS]
    INT21h/Fn4Ah		DOS 2+

In:	AX = 4Ah
    BX = new size of block
    WHERE PLACED BLOCK ???
Out:	if CF = 0 success
    if CF = 1 error
        AX = error code
        BX = max available block (in paragraphs)
----------------------------------------------------------
get allocation strategy 5800h [DOS]
    INT21h/Fn5800h		DOS 3+

In:	AX = 5800h
Out:	AX = current strategy
        00h	low memory first fit
        01h	low memory best fit
        02h	low memory last fit
        40h	high memory, first fit
        41h	high memory, best fit
        42h	high memory, last fit
        80h	first fit, high then low
        81h	best fit,  high then low
        82h	last fit,  high then low
----------------------------------------------------------
set allocation strategy 5801h [DOS]
    INT21h/Fn5801h		DOS 3+

In:	AX = 5801h
    BL = new strategy (see INT21h/Fn5800h)
    BH = 00h
Out:	if CF = 0 success
    if CF = 1 error
        AX = error code
----------------------------------------------------------

Кстати наверняка будет интересно посмотреть на структуру кучи DOS:

----------------------------------------------------------
DOS MCB  (Memory control block)

+00	BYTE	Block type
        5Ah  if last block in chain
        4Dh  overwise
+01	WORD	PSP segment of owner or special flag value
        0000 = free
        0008 = allocated by DOS
+03	WORD	Size of block in paragraphs
+05	3BYTEs	Unused
+08	8BYTEs	ASCII program name if PSP memory block
----------------------------------------------------------

  Виртуальная сегментная память

В операционных системах которые поддерживают сегментную виртуальную память,
но не поддерживают виртуальную страничную память.
(Типовые примеры Windows 3.x [Win16], OS/2 1.x, 2.x, MacOS [не путать с Mac OS X].

Память находится в сегментах - подряд идущих зонах памяти.
Свойства сегмента:

  Fixed segment

Fixed     - находится на конкретных адрессах физической памяти

  Moveable segment

Moveable  - OS может перемещать сегмент, но тем не менее он остается
        в памяти

  Discardable segment

Discardable - OS может сбрасывать сегмент в Page file итд

  Жизнь сегмента

Рассмотрим на примере Win16 API:
Global API для памяти, то есть селекторы аллокируются в GDT, а не в LDT (и как следствие
доступны всем процессам). Для Local памяти абсолютно такие же функции только они начинаются
с слова Local, а не Global.

HANDLE WINAPI GlobalAlloc(WORD dwFlags,
              DWORD dwBytes);

    // dwFlags:
    //	GMEM_DISCARDABLE
    //	GMEM_FIXED
    //	GMEM_MOVEABLE
    //	GMEM_NOCOMPACT
    //	GMEM_NODISCARD
    //	GMEM_NOTIFY
    //	GMEM_ZEROINIT

    Этой функцией можно выделить и больше 64K. В этом случае в 16-бит targets
    строют несколько селекторов подряд.

HANDLE WINAPI GlobalFree(HANDLE hMem);

HANDLE WINAPI GlobalReAlloc(HANDLE hMem,
                DWORD  dwBytes,
                WORD   wFlags);

DWORD  WINAPI GlobalSize(HANDLE hMem);

WORD   WINAPI GlobalFlags(HANDLE hGlobalMem);

HANLDE WINAPI GlobalDiscard(HANDLE hMem);

VOID   WINAPI GlobalFix(HANDLE hMem);
VOID   WINAPI GlobalUnfix(HANDLE hMem);

LPSTR  WINAPI GlobalLock(HANDLE hMem);
BOOL   WINAPI GlobalUnlock(HANDLE hMem);

DWORD  WINAPI GlobalCompact(DWORD dwMinSize);	// Пытается компактизировать память, что бы
                        // выделить в идущее подряд свободное
                        // пространство dwMinSize байтов

Компактизация адрессного пространства:

  Виртуальная страничная память

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

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

    Резервирование адрессного пространства

    Для драйверов:
        Paged/Non-Paged pool
        Копирование из user space
        Копирование из другово процесса
    Локирование памяти
        запрещение памяти перемещаться

    Возможно:
        перемещение
        сбрасывание (в Page File)
    Свойства памяти
    Защита памяти
        свойства:
            read/write/execute
    copy-on-write

    Выделение виртуальной памяти
        аллокирование группы страниц в адрессном пространстве

  Свойства страниц

    Access:
        Read
        Write
        Execute
        No Access
        Guard

x86 процессоры (legacy вариант):

x86 процессоры (новый вариант) и x64:

ia64 процессоры:

    Cachebility:
        No caching
        Caching
            Write Through
            Write Back
        Write combine

на эту тему можно прочитать в секции 81.2.1. ФИЗИЧЕСКАЯ ПАМЯТЬ

  Состояния страниц виртуальной памяти

  Free page

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

  Reserved page

Зарезервированная страница - не отмапирована на физическую.
Выделять нельзя (адресное пространство уже выделено).
Но можно либо освободить либо перевести в Commit состояние.

  Guard page

Guard page - при обращение к странице OS бросает приложению
специальный exception.

  Stack Guard

Особый случай для Guard page - это Stack Guard.
Страницы для стека потока выделяются исключительно по
необходимости.

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

Поэтому если известно что функция суммарно кушает более страницы, то аллокацию
делают через функцию _chkstk

    public _chkstk
_chkstk proc

    push 	ecx

    ; Calculate new TOS.

    lea ecx, [esp] + 8 - 4  ; TOS before entering function + size for ret value
    sub ecx, eax 		; new TOS

; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.

    sbb eax, eax 		; 0 if CF==0, ~0 if CF==1
    not eax 		; ~0 if TOS did not wrapped around, 0 otherwise

    and ecx, eax 		; set to 0 if wraparound
    mov eax, esp 		; current TOS
    and eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary

cs10:
    cmp  ecx, eax 		; Is new TOS
    jb   short cs20 	; in probed page?
    mov  eax, ecx 		; yes.
    pop  ecx
    xchg esp, eax 		; update esp
    mov   eax, dword ptr [eax] ; get return address
    mov dword ptr [esp], eax ; and put it at new TOS
    ret

; Find next lower page and probe

cs20:
    sub eax, _PAGESIZE_  	 ; decrease by PAGESIZE
    test dword ptr [eax],eax ; probe page.
    jmp short cs10

_chkstk endp

  Commit page

Находящяяся в памяти:
Можно перемещать.
Есть доступ.

Находящаяся на диске

  Locked page

Находится в памяти
Физический адресс фиксирован

  Windows

Для получения размера страницы можно использовать функцию:

void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);

struct SYSTEM_INFO содержит поля:
    DWORD dwPageSize;
    DWORD dwNumberOfProcessors;

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

 Windows

LPVOID WINAPI VirtualAlloc(LPVOID lpAddress,
                    SIZE_T dwSize,
                    DWORD flAllocationType,
                    DWORD flProtect);

    // flAllocationType:
    //		MEM_COMMIT	выделить память
    //		MEM_RESERVE	просто зарезвировать адресное пространство
    //		MEM_RESET	игнорировать
    //
    //		MEM_LARGE_PAGES
    //		MEM_PHYSICAL	выделить страницы которые потом будут отображаться
    //				в физическую память (читай секцию про окна памяти)
    //		MEM_TOP_DOWN	аллокировать на самом большом доступном адрессе
    //		MEM_WRITE_WATCH

    // flProtect:
    //		PAGE_EXECUTE
    //		PAGE_EXECUTE_READ
    //		PAGE_EXECUTE_READWRITE
    //		PAGE_EXECUTE_WRITECOPY
    //		PAGE_NOACCESS
    //		PAGE_READONLY
    //		PAGE_READWRITE
    //		PAGE_WRITECOPY
    //
    //		PAGE_GUARD
    //		PAGE_NOCACHE
    //		PAGE_WRITECOMBINE

BOOL WINAPI VirtualFree(LPVOID lpAddress,
                 SIZE_T dwSize,
                  DWORD dwFreeType);

    // dwFreeType:
    //		MEM_DECOMMIT
    //		MEM_RELEASE	// do not use with MEM_DECOMMIT

CODE

// Commit at any place
#include <windows.h>
#include <iostream.h>

int __cdecl main()
{
    int* p;
    const int size = 1024;

    p = VirtualAlloc(NULL,
             size,
             MEM_COMMIT,
             PAGE_READWRITE);

    if (!a)
    {
        cout << "Allocation failed\n" << endl;
        return	GetLastError();
    }

    cout << "Address is " << p << endl;

    if (!VirtualFree(p, 0, MEM_RELEASE))
    {
        cout  << "Release Failed\n");
        return	GetLastError();
    }

    return	0;
}

CODE

// Commit at specified place
#include <windows.h>
#include <iostream.h>

int __cdecl main()
{
    int* p;
    const int size = 1024;

    p = VirtualAlloc((LPVOID) 0x00990002,
             size,
             MEM_COMMIT | MEM_RESERVE,
             PAGE_READWRITE);

    if (!a)
    {
        cout << "Allocation failed\n" << endl;
        return	GetLastError();
    }

    cout << "Address is " << p << endl;

    if (!VirtualFree(p, 0, MEM_RELEASE))
    {
        cout  << "Release Failed\n");
        return	GetLastError();
    }

    return	0;
}

CODE

#include <windows.h>
#include <iostream.h>

int __cdecl main()
{
    LPVOID lpr;
    LPVOID lpc;
    const int size = 1024;

    lpr = VirtualAlloc((LPVOID) 0x00990000,
             size,
             MEM_RESERVE,
             PAGE_READWRITE);

    if (!a)
    {
        cout << "Reserve failed\n" << endl;
        return	GetLastError();
    }

    cout << "Address is " << p << endl;

    lpc = VirtualAlloc((LPVOID) 0x00990000,
               size,
               MEM_COMMIT,
               PAGE_READWRITE);

    if (!lpc)
    {
        cout << "Commit failed" << endl;
        return	GetLastError();
    }

    if (!VirtualFree(lpc  size, MEM_DECOMMIT)
    {
        count << "Decommit failed" << endl;
        return	GetLastError();
    }

    if (!VirtualFree(lpr, 0, MEM_RELEASE))
    {
        cout  << "Release Failed" << endl);
        return	GetLastError();
    }

    return	0;
}

CODE

    int* lp = (int*) VirtualAlloc(NULL,
                        size,
                        MEM_COMMIT,
                        PAGE_READWRITE | PAGE_GUARD);
    __try
    {
        lp[0] = 0;

    } __except(EXCEPTION_EXECUTE_HANDLER)
    {
        DWORD ecode = GetExceptionCode();

        if (ecode == EXCEPTION_GUARD_PAGE)
        {
            // Access to guarded pages
        }
    }

 Windows

SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress,
                           PMEMORY_BASIC_INFORMATION lpBuffer,
                           SIZE_T dwLength);

    typedef struct _MEMORY_BASIC_INFORMATION
    {
        PVOID BaseAddress;
        PVOID AllocationBase;
        DWORD AllocationProtect;
        SIZE_T RegionSize;
        DWORD State;  		// MEM_COMMIT/MEM_FREE/MEM_RESERVE
        DWORD Protect;
        DWORD Type;		// MEM_IMAGE/MEM_MAPPED/MEM_PRIVATE
    } MEMORY_BASIC_INFORMATION,  *PMEMORY_BASIC_INFORMATION;

 Windows

BOOL WINAPI VirtualProtect(LPVOID lpAddress,
                SIZE_T dwSize,
                     DWORD flNewProtect,
                    PDWORD lpflOldProtect);

 Windows

BOOL WINAPI VirtualLock(LPVOID lpAddress,
                 SIZE_T dwSize);

BOOL WINAPI VirtualUnlock(LPVOID lpAddress,
               SIZE_T dwSize);

 Windows

BOOL WINAPI SetProcessWorkingSetSize(
              HANDLE hProcess,
              SIZE_T dwMinimumWorkingSetSize,
              SIZE_T dwMaximumWorkingSetSize);

BOOL WINAPI GetProcessWorkingSetSize(
            HANDLE hProcess,
            PSIZE_T lpMinimumWorkingSetSize,
        PSIZE_T lpMaximumWorkingSetSize);

Помните под Windows вы можите залочить только:
PAGES(MinimumWorkingSetSize) - 8 страниц памяти.
Поэтому если вам надо много корректируйте Working Set Size.

 Windows

LPVOID WINAPI VirtualAllocEx(
          HANDLE hProcess,
          LPVOID lpAddress,
          SIZE_T dwSize,
          DWORD flAllocationType,
          DWORD flProtect);

BOOL WINAPI VirtualFreeEx(
          HANDLE hProcess,
          LPVOID lpAddress,
          SIZE_T dwSize,
          DWORD dwFreeType);

BOOL WINAPI VirtualProtectEx(
          HANDLE hProcess,
          LPVOID lpAddress,
          SIZE_T dwSize,
          DWORD flNewProtect,
          PDWORD lpflOldProtect);

  Memory Mapped Files

Собственно для кучи можно использовать также функции маппинга, тогда будет
использоваться page file.

 Windows

HANDLE WINAPI CreateFileMapping(			// что бы использовать page file
  __in          HANDLE hFile,				// INVALID_HANDLE_VALUE
  __in          LPSECURITY_ATTRIBUTES lpAttributes,
  __in          DWORD flProtect,
  __in          DWORD dwMaximumSizeHigh,
  __in          DWORD dwMaximumSizeLow,
  __in          LPCTSTR lpName);			// NULL

LPVOID WINAPI MapViewOfFile(
  __in          HANDLE hFileMappingObject,
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwFileOffsetHigh,
  __in          DWORD dwFileOffsetLow,
  __in          SIZE_T dwNumberOfBytesToMap
);

LPVOID WINAPI MapViewOfFileEx(				// можем отмаппить на конкретный
  __in          HANDLE hFileMappingObject,		// адресс
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwFileOffsetHigh,
  __in          DWORD dwFileOffsetLow,
  __in          SIZE_T dwNumberOfBytesToMap,
  __in          LPVOID lpBaseAddress
);

BOOL WINAPI UnmapViewOfFile(
  __in          LPCVOID lpBaseAddress
);

BOOL WINAPI FlushViewOfFile(
  __in          LPCVOID lpBaseAddress,
  __in          SIZE_T dwNumberOfBytesToFlush
);

HANDLE WINAPI OpenFileMapping(
  __in          DWORD dwDesiredAccess,
  __in          BOOL bInheritHandle,
  __in          LPCTSTR lpName
);

DWORD WINAPI GetMappedFileName(
  __in          HANDLE hProcess,
  __in          LPVOID lpv,
  __out         LPTSTR lpFilename,
  __in          DWORD nSize
);

CODE

#include <windows.h>

int __cdecl main()
{
    HANDLE	hFile = CreateFile(filename,
                  GENERIC_READ | GENERIC_WRITE,
                  0,
                  NULL,
                  OPEN_EXISTING,
                  FILE_ATTRIBUTE_NORMAL,
                  NULL);

    if (hFile == INVALID_HANDLE_VALUE)
    {
        return	GetLastError()
    }

    hMap = CreateFileMapping(hFile,
                NULL,
                PAGE_READWRITE,
                0,0,		// same as file size
                NULL);

    if (!hMap)
    {
        return	GetLastError();
    }

    LPVOID p = MapViewOfFile(hMap, FILE_MAP_WRITE, 0,0,0);
    if (!p)
    {
        return	GetLastError();
    }

    // Here we work with file in memory

    // Flush need only if we modify this zone
    if (!FlushViewOfFile(p, GetFileSize(hFile, NULL)))
    {
        return	GetLastError();
    }

    if (!(UnmapViewOfFile(p))
    {
        return	GetLastError();
    }

    if (!(CloseHandle(hMap))
    {
        return	GetLastError();
    }

    // if we want to change file size, we must do it only then all mappings
    // handles will closed.

    if (SetFilePointer(hFile, newsize, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
    {
        return	GetLastError();
    }

    if (!SetEndOfFile(hFile))
    {
        return	GetLastError();
    }

    if (!(CloseHandle(hFile))
    {
        return	GetLastError();
    }
    return	0;
}

В Win32 секция расти не может (то есть размер жестко такой как
при создании. Но в Native API это сделать можно, при условии что
секция отмаплена в реальный файл данных (а не в page file или executable).

 Windows

NTSTATUS NTAPI NtExtendSection(IN HANDLE SectionHandle,
                   IN PLARGE_INTEGER NewSize);

Кроме этого есть возможность запросить информацию о секции:
    NtQuerySection

  Неравнозначность памяти на NUMA системах

У SMP время доступа к памяти одинаково на всех процессорах.

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

 Windows

LPVOID WINAPI VirtualAllocExNuma(
          HANDLE hProcess,
          LPVOID lpAddress,
          SIZE_T dwSize,
            DWORD flAllocationType,
              DWORD flProtect,
              DWORD nndPreferred);	// NUMA node, where physical memomy should reside

BOOL WINAPI GetNumaAvailableMemoryNode(
  __in          UCHAR Node,
  __out         PULONGLONG AvailableBytes
);

BOOL WINAPI GetNumaHighestNodeNumber(
  __out         PULONG HighestNodeNumber
);

BOOL WINAPI GetNumaNodeProcessorMask(
  __in          UCHAR Node,
  __out         PULONGLONG ProcessorMask
);

BOOL WINAPI GetNumaProcessorNode(
  __in          UCHAR Processor,
  __out         PUCHAR NodeNumber
);

BOOL WINAPI AllocateUserPhysicalPagesNuma(
  __in          HANDLE hProcess,
  __in_out      PULONG_PTR NumberOfPages,
  __out         PULONG_PTR PageArray,
  __in          DWORD nndPreferred
);

NUMA функции для memory mapped files.

 Windows

HANDLE WINAPI CreateFileMappingNuma(
  __in          HANDLE hFile,
  __in          LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
  __in          DWORD flProtect,
  __in          DWORD dwMaximumSizeHigh,
  __in          DWORD dwMaximumSizeLow,
  __in          LPCTSTR lpName,
  __in          DWORD nndPreferred
);

LPVOID WINAPI MapViewOfFileExNuma(
  __in          HANDLE hFileMappingObject,
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwFileOffsetHigh,
  __in          DWORD dwFileOffsetLow,
  __in          SIZE_T dwNumberOfBytesToMap,
  __in          LPVOID lpBaseAddress,
  __in          DWORD nndPreferred
);

  UNIX

  brk()/sbrk()

Старые имплементации UNIX:

 UNIX

// unistd.h
int brk(void *end_data_segment);

void *sbrk(ptrdiff_t increment);

brk - set end of data segment
    return	0 on success
        -1 on fail
            errno = ENOMEM
sbrk - increment data segment
    (sbrk - это не системный вызов, а библиотечная функция)
        return -1 if fail

Кстати sbrk и brk - могут как увеличивать так и уменьшать границу
для данных.

Начальный адресс сегмента кучи программа узнает читая переменную c именем 'end',
которую создает линкер.
В дальнейшем sbrk() использует переменную __curbrk, для того что бы хранить адресс.

Кстати sbrk(0) возвращает текущее значение break указателя.

  mmap() interface

В настоящее время предпочитают пользоваться mmap()

 UNIX

// sys/mman.h
void* mmap(void*  start,
       size_t length,
       int    prot,
       int    flags,
       int	  fd,
       off_t  offset);

    // prot is:
    //	PROT_READ
    //	PROT_WRITE
    //	PROT_EXEC
    //	PROT_NONE

    // flags is:
    //	MAP_SHARED
    //	MAP_PRIVATE
    //	MAP_FIXED
    //	MAP_NORESERVE
    //	MAP_ANON
    //	MAP_ALIGN	интерпретировать start как align
    //	MAP_TEXT
    //	MAP_INITDATA

int   munmap(void* start,
         off_t offset);

void *mremap(void *old_address, size_t old_size,
             size_t new_size, int flags);

int   mprotect(void *addr, size_t len, int prot);

int   mlock(const void * addr, size_t len);
int   munlock(const void * addr, size_t len);

int   mlockall(int flags);
    // flags is:
    //	MCL_CURRENT	все которые есть в address space процесса
    //	MCL_FUTURE	и все которые будут в будущем

int   munlockall(void);

int   msync(void *addr, size_t len, int flags);
    // flags is:
    //	MS_ASYNC
    //	MS_SYNC
    //	MS_INVALIDATE

 UNIX

int   madvice(void* addr, size_t len, int advice);  // нестандартная - дает hints
    // advice is:
    //	MADV_NORMAL
    //	MADV_RANDOM
    //	MADV_SEQUENTIAL
    //	MADV_WILLNEED
    //	MADV_DONTNEED

Как использовать mmap() для аллокации памяти для кучи

    mmap(NULL,	 	// неважно где
         length,		// длинна (надо выровнять на резмер страницы)
         PROT_READ|PROT_WRITE,
         MAP_ANONYMOUS|MAP_PRIVATE,
         (-1),		// нет файл дескриптора
         0);		// все равно какой оффсет

 UNIX

// sys/resource.h

int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);

struct rlimit
{
    rlim_t rlim_cur;  /* Soft limit */
    rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */
};

RLIMIT_DATA	-  maximum size of process data segment
RLIMIT_MEMLOCK  -  maximum number of bytes, which can be locked
RLIMIT_STACK	-  maximum size of process stack

  System V Shared Memory

 UNIX

//sys/ipc.h
key_t ftok(const char* path, int fd);

//sys/shm.h
// return shared memory identifier
int shmget(key_t key, size_t size, int flag);

int shmctl(int shmid, int cmd, struct shmid_ds* buf);
    // cmd is:
    //	IPC_STAT
    //	IPC_SET
    //	IPC_RMID	delete
    //		Linux, Solaris:
    //		IPC_LOCK
    //		IPC_UNLOCK

struct shmid_ds
{
    struct  ipc_perm shm_perm;
    size_t           shm_segsz;
    pid_t            shm_lpid;
    pid_t		 shm_cpid;
    smattr_t	 shm_nattch;
    time_t		 shm_atime;
    time_t		 shm_dtime;
    time_t		 shm_ctime;
};

// attach to address space
void* shmat(int shmid, const void* addr, int flags);

int   shmdt(void* addr);

  POSIX Shared Memory

 UNIX

// sys/mman.h
int shm_open(const char* name,
         int   flags,
         mode_t perm);

int shm_unlink(const char* name);

int ftruncate(int fd, off_t length);

// For mapping shared memory used mmap() system call


81.2.5. ОРГАНИЗАЦИЯ ВИРТУАЛЬНОЙ ПАМЯТИ НА X86

Для общего понимания опишем здесь кратко как работает система
виртуальной памяти на процессорах семейства x86.
(Причем не будем бросаться в современные extentions).

  Сегментная виртуальная память

---------------------------
Bit	Description
---------------------------
G	Granularity (scale limit)
D	Default operand size
P	Present
DPL	Priveledge level
C	Conformed
R	Readable
A	Accessed
---------------------------

---------------------------
Bit	Description
---------------------------
G	Granularity (scale limit)
D	Default operand size
P	Present
DPL	Priveledge level
E	Expand down
W	Writable
A	Accessed
---------------------------

  Страничная виртуальная память

  4K legacy

регистр CR3:

---------------------------
Bit	Description
---------------------------
P	Present
R/W	Read/Write
U/S	User/Supervisor
PWT	Page Write through
PCD	Page Cache disable
A	Accessed
D	Dirty
PAT	Page Attribut table (caching)
G	Global
---------------------------

При первой обращение к странице ставиться флаг A.
При первой записе к странице ставиться флаг D.

  4M pages

  4K pages PAE

  2M pages PAE

  Глобальные страницы

Что бы не обращаться при каждом обращении к памяти к таблицам страниц
у процессора есть для них кэш TLB (Translation Lookaside Buffer).

Если TLB Hit, то адресс береться из TLB.
Если TLB Miss, то адресс выбирается из Page tables.

Поэтому большие размеры страниц хороши с точки зрения быстродействия системы.

При переключение процесса (не нити - нити работают в пределах одного процесса)
происходит перезагрузка указателя на таблицу страниц (и при этом сбрасываются все
входы в TLB [кроме глобальных].

Но системное адрессное пространство маппиться во все процессы.
Поэтому хочеться что бы входы в TLB для страниц относящиеся к системному пространству
не сбрасывались при переключении задач.

Для этого и сделали в страницах Global Flag.

    ; Flush TLB  (except global pages)

    mov	eax, cr3
    mov	cr3, eax

    ; Flush TLB  (include global pages)
    mov	eax, cr4
    and	eax, 0ffffff7fh		; clear CR4.PGE
    mov	cr4, eax
    mov	eax, cr3
    mov	cr3, eax
    mov	eax, cr4
    or	eax, 80h		; set CR4.PGE
    mov	cr4, eax

Для того чтобы сбросить из TLB конкретную страницу
используют инструкцию:

    INVLPG	addr


81.2.6. ПАМЯТЬ С ТОЧКИ ЗРЕНИЯ ДРАЙВЕРОВ И ОПЕРАЦИОННОЙ СИСТЕМЫ

Память:
    Paged	  (может свопаться на диск и не присутсвовать в физической памяти).
          Доступ к paged памяти доступен не всегда,
          например если уже идет подкачка страницы то отсутсвие страницы в памяти
          вызовет panic
          Особенно это характерно для драйверов storage устройств
    NonPaged  (всегда находиться в физической памяти)

Адрессное пространство:
    Kernel	   доступно всегда
    User	   отмаплено на какой то процесс

  Квоты памяти процессов

У процессов есть квоты на использования памяти
(У ядра как правило нету).

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

 Windows

PVOID
  ExAllocatePoolWithQuota(
    IN POOL_TYPE  PoolType,
    IN SIZE_T  NumberOfBytes
    );

  Передача данных между Kernel/User Space

Нить в ядре может работать в контексте какого-то процесса (т.е. user address space
отмаплен на конкретный process), или в системном контексте (user address space отмаплен
на последний выполнявшийся процесс на этом ядре, и может переодически меняться).

Копирование памяти из пространства пользователя
Копирование памяти в  пространство пользователя

 UNIX

    int	copyin(caddr_t from,
               caddr_t to,
               unsigned int cnt);

    int	copyout(caddr_t from,
            caddr_t to,
            unsigned int cnt);

Для Windows:
METHOD_BUFFERED		система сама буферизирует в Kernel Address Space
METHOD_IN_DIRECT	MDL
METHOD_OUT_DIRECT	MDL
METHOD_NEIGHER		просто виртуальный указатель на память user mode.

    Выделение/освобождение памяти в пространстве пользователя

 Windows

NTSTATUS  NTAPI NtAllocateVirtualMemory(
    IN	HANDLE	ProcessHandle,
    IN OUT  PVOID*	BaseAddress,
    IN	ULONG	ZeroBits,
    IN OUT	ULONG	AllocationType,
    IN	ULONG   Protect);

NTSTATUS NTAPI NtFreeVirtualMemory(
    IN	HANDLE	ProcessHandle,
    IN 	PVOID*	BaseAddress,
    IN	PULONG	RegionSize,
    IN	ULONG	FreeType);

    Подсоединение user address space для указанного процесса.

 Windows

VOID 	  KeAttachProcess(IN PEPROCESSS Process);
VOID 	  KeDetachProcess(VOID);
PEPROCESS IoGetCurrentProcess(VOID);

  Драйверы и физическая память

Физическая память.
    Bus Master устройства работают именно с ней.
    Собственно имеем 2 типа устройств:
        Требующие непрерывный блок памяти
        Поддерживающие Scatter/Gather
    Кроме этого есть проблемы с адресацией памяти устройствами
        Например ISA16 устройство не может адрессовать более 16MB памяти
        32-бит PCI устройство не может адресовать более 4GB памяти
        Бывают и другие ограничения

    Преобразование виртуальных адрессов в физические

    Выделение/Освобождение физической памяти
        по указанным физическим адрессам
        в определенных границах

    Не все устройства поддерживают Scatter/Gather. Для некоторых нужен
    непрерывный кусок физической памяти.

 Windows

PVOID
  MmAllocateNonCachedMemory(
    IN SIZE_T  NumberOfBytes
    );

VOID
  MmFreeNonCachedMemory(
    IN PVOID  BaseAddress,
    IN SIZE_T  NumberOfBytes
    );

// Allocate physical contiguous memory
PVOID
  MmAllocateContiguousMemory(
    IN SIZE_T  NumberOfBytes,
    IN PHYSICAL_ADDRESS  HighestAcceptableAddress
    );

VOID
  MmFreeContiguousMemory(
    IN PVOID  BaseAddress
    );

PVOID
  MmAllocateContiguousMemorySpecifyCache(
    IN SIZE_T  NumberOfBytes,
    IN PHYSICAL_ADDRESS  LowestAcceptableAddress,
    IN PHYSICAL_ADDRESS  HighestAcceptableAddress,
    IN PHYSICAL_ADDRESS  BoundaryAddressMultiple  OPTIONAL,
    IN MEMORY_CACHING_TYPE  CacheType
    );

typedef enum _MEMORY_CACHING_TYPE {
  MmNonCached,
  MmCached,
  MmWriteCombined
} MEMORY_CACHING_TYPE;

NTKERNELAPI VOID
  MmFreeContiguousMemorySpecifyCache(
    IN PVOID  BaseAddress,
    IN SIZE_T  NumberOfBytes,
    IN MEMORY_CACHING_TYPE  CacheType
    );

// Map contignous Physical to Virtual

PVOID
  MmMapIoSpace(
    IN PHYSICAL_ADDRESS  PhysicalAddress,
    IN SIZE_T  NumberOfBytes,
    IN MEMORY_CACHING_TYPE  CacheType
    );

VOID
  MmUnmapIoSpace(
    IN PVOID  BaseAddress,
    IN SIZE_T  NumberOfBytes
    );

// Map MDL to system addresses
PVOID MmGetSystemAddressForMdl(IN PMDL Mdl);

// Map MDL virtual to physical
PVOID
  MmMapLockedPages(
    IN PMDL  MemoryDescriptorList,
    IN KPROCESSOR_MODE  AccessMode
    );

VOID
  MmUnmapLockedPages(
    IN PVOID  BaseAddress,
    IN PMDL  MemoryDescriptorList
    );

struct	MDL
{
    PMDL	Next;
    CSHORT	Size;
    CSHORT	MdlFlags;
    PEPROCESS Process;
    PVOID	MappedSystemVa;
    PVOID	StartVa;
    ULONG	ByteCount;
    ULONG	ByteOffset;
};

 UNIX

// Аллокирование страниц в ядре (страницы смежные физически)

void * kmalloc(size_t size, int flags);
void   kfree(const void* ptr);

// Страницы смежны только виртуально

void * vmalloc(unsigned long size)
void   vfree(void* addr)

// Мапирование физических страниц в виртуальные в ядре

void* kmap(struct page* page)
void  kunmap(struct page* page)

Об управление операционной системой виртуальной памяти можно прочитать
в секции 80.1.3.2. ПРОЦЕССЫ И УПРАВЛЕНИЕ ВИРТУЛЬНОЙ ПАМЯТЬЮ


81.2.7. СТРУКТУРНАЯ ОРГАНИЗАЦИЯ ПАМЯТИ В ОПЕРАЦИОННЫХ СИСТЕМАХ

  Типы страниц виртуальной памяти

Строго говоря о виртуальной памяти в операционных системах бывает 3 различных
типа памяти:

1) Страницы относящиеся к адресному пространству ядра.
   Поскольку все процессы разделяют одно и тоже адрессное пространсво ядра,
   то они используют одни и теже page tables для пространства
   ядра (их Page Directory Table ссылается на page tables для ядра),
   то проблем нет - любые изменения можно делать только в одном месте,
   и все процессы их увидят.
   (Для outswapped pages - индекс в Page-file хранят прямо в PTE).
   (Обычно еще входы в PDE делают not-present, и только когда процесс хочет
    обратиться к странице копируют туда вход из основного главного PDE системы).

2) Приватные страницы памяти принадлежащие только одному процессе
   Тоже нет проблем - как правило все халявщики - индекс хранения для Page File
   кладется прямо в Page Table entry.
   Это конечно накладывает ограничения на суммарный размер swap.
   Например для x86 4K legacy pages при такой схеме в Windows максимальный swap
   может быть не больше 12 bit (размер страницы) + 24 bit (swap index)
   = 36 bit  (то есть не более 64GB).
   При использовании PTE больших размеров размеры swap при этой схеме уже
   могут достигать терабайтов.

3) Разделяемая память.
   Тут есть 2 варианта:
    A) Приватная память разделяемая между двумя и более процессами
    B) Memory-mapped files
        как явно отмапированные
        так и отмапированные секции выполняемых файлов.
   В этих случаях не обойдешься только хранением индекса для page file.
   Приходиться использовать структуры ассоциированные с PPD (Physical Page
   Database)

  Базовые и небазовые загрузки образов

С отмапированными секциями выполняемых файлов есть ньюансы.
Образ секции можно успешно разделять если исполняемый файл или DLL загружены
по базовому адрессу который был указан при сборке.
В этом случае секции DATA и CODE можно непосредсвенно грузить с диска.
(И по этому базовые DLLs Windows имеют различные базовые адресса).

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

Естественно когда эти изменения применены то секции DATA и CODE в памяти отличаются
от этих секций на диске. В этом случае их будет свопать в page file, а не подгружать
из исполняемого файла, так как перенастроить страницу секции из образа очень неприятное
и долгое занятие (не говоря о том что для этого нужна куча таблиц, которые придеться
грузить из исполняемого файла).

(Реально ситуация сложнее: так как система может грузить DLL в кучу процессов по
другому адрессу и sharить подпатченный образ).

NOTE

Система свопает по любому образы которые запущены с Floppy диска,
или образы собранные с флагами /SWAPRUN:CD или /SWAPRUN:NET запущенные с CD/DVD или
с сети соответсвенно.

  Использование PTE  на примере Windows

// Legacy 4K
typedef struct _MMPTE_HARDWARE {
    ULONG Valid : 1;
    ULONG Writable : 1;      //changed for MP version
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Accessed : 1;
    ULONG Dirty : 1;
    ULONG LargePage : 1;
    ULONG Global : 1;
    ULONG CopyOnWrite : 1; // software field
    ULONG Prototype : 1;   // software field
    ULONG Write : 1;       // software field - MP change
    ULONG PageFrameNumber : 20;
} MMPTE_HARDWARE, *PMMPTE_HARDWARE;

// PAE
typedef struct _MMPTE_HARDWARE {
    ULONGLONG Valid : 1;
    ULONGLONG Writable : 1;        // changed for MP version
    ULONGLONG Owner : 1;
    ULONGLONG WriteThrough : 1;
    ULONGLONG CacheDisable : 1;
    ULONGLONG Accessed : 1;
    ULONGLONG Dirty : 1;
    ULONGLONG LargePage : 1;
    ULONGLONG Global : 1;
    ULONGLONG CopyOnWrite : 1; // software field
    ULONGLONG Prototype : 1;   // software field
    ULONGLONG Write : 1;       // software field - MP change
    ULONGLONG PageFrameNumber : 24;
    ULONGLONG reserved1 : 28;  // software field
} MMPTE_HARDWARE, *PMMPTE_HARDWARE;

Windows использует два своих флага:
    T - Transition  - страница в переходном состоянии
              то есть либо outswappиться либо inswappиться
              прямо сейчас.
              (возможно у всех страниц)
    PTT - Prototype - страница описана в специальной системной таблице
              прототипов страниц
              (используется только для shared memory)
    COW - Copy on Write

// Legacy 4K
typedef struct _MMPTE_SOFTWARE {
    ULONG Valid : 1;
    ULONG PageFileLow : 4;
    ULONG Protection : 5;
    ULONG Prototype : 1;
    ULONG Transition : 1;
    ULONG PageFileHigh : 20;
} MMPTE_SOFTWARE;

// PAE
typedef struct _MMPTE_SOFTWARE {
    ULONGLONG Valid : 1;
    ULONGLONG PageFileLow : 4;
    ULONGLONG Protection : 5;
    ULONGLONG Prototype : 1;
    ULONGLONG Transition : 1;
    ULONGLONG Unused : 20;
    ULONGLONG PageFileHigh : 32;
} MMPTE_SOFTWARE;

// Legacy 4K
typedef struct _MMPTE_TRANSITION {
    ULONG Valid : 1;
    ULONG Write : 1;
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Protection : 5;
    ULONG Prototype : 1;
    ULONG Transition : 1;
    ULONG PageFrameNumber : 20;
} MMPTE_TRANSITION;

// PAE
typedef struct _MMPTE_TRANSITION {
    ULONGLONG Valid : 1;
    ULONGLONG Write : 1;
    ULONGLONG Owner : 1;
    ULONGLONG WriteThrough : 1;
    ULONGLONG CacheDisable : 1;
    ULONGLONG Protection : 5;
    ULONGLONG Prototype : 1;
    ULONGLONG Transition : 1;
    ULONGLONG PageFrameNumber : 24;
    ULONGLONG Unused : 28;
} MMPTE_TRANSITION;

// Legacy 4K
typedef struct _MMPTE_PROTOTYPE {
    ULONG Valid : 1;
    ULONG ProtoAddressLow : 7;
    ULONG ReadOnly : 1;  // if set allow read only access.
    ULONG WhichPool : 1;
    ULONG Prototype : 1;
    ULONG ProtoAddressHigh : 21;
} MMPTE_PROTOTYPE;

// PAE
typedef struct _MMPTE_PROTOTYPE {
    ULONGLONG Valid : 1;
    ULONGLONG Unused0: 7;
    ULONGLONG ReadOnly : 1;  // if set allow read only access.  LWFIX: remove
    ULONGLONG Unused1: 1;
    ULONGLONG Prototype : 1;
    ULONGLONG Protection : 5;
    ULONGLONG Unused: 16;
    ULONGLONG ProtoAddress: 32;
} MMPTE_PROTOTYPE;

// Legacy 4K
typedef struct _MMPTE_SUBSECTION {
    ULONG Valid : 1;
    ULONG SubsectionAddressLow : 4;
    ULONG Protection : 5;
    ULONG Prototype : 1;
    ULONG SubsectionAddressHigh : 20;
    ULONG WhichPool : 1;
} MMPTE_SUBSECTION;

// PAE
typedef struct _MMPTE_SUBSECTION {
    ULONGLONG Valid : 1;
    ULONGLONG Unused0 : 4;
    ULONGLONG Protection : 5;
    ULONGLONG Prototype : 1;
    ULONGLONG Unused1 : 21;
    ULONGLONG SubsectionAddress : 32;
} MMPTE_SUBSECTION;

  Структуры управления памятью

Виртуальное адрессное пространство:
    Адрессное пространство процесса
    Адрессное пространство системы

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

Назовем ее PASD (Process Address Space Descriptor).
Что же в себе должен содержать PASD?

    1.
    Очевидно что указатель на физическую страницу где храниться PDT (Page Directory Table)
    для этого процесса. Потому что системе надо:
        грузить этот адресс в CR3
        иметь к ней доступ с целью модификации

    2.
    Указатель на список-дерево структур VAD (Virtual Address Descriptor),
    которые описывают регион виртуальной памяти.

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

VAD (Virtual Address Descriptor)

Что должен описывать VAD?

        1.
    Стартовый линейный образ области

    2.
    Размер области в байтах

    3.
    Флаги описывающии область
    (ну там защита, reserved, кэширование)

    4.
    Указатель на массив указателей на страницы в базе данных физических страниц (PPD)

    5.
    Количество активных страниц в этом массиве

    6.
    Указатели на предидущую и следующую VAD структуру
    Ну и связи для дерева

    7.
    Если зона отображена на файл (отличный от swap file) то:
        Указатель на открытый объект отображаемого файла
        Смещение начала VAD области в отображаемом файле.

Свойства страницы виртуального адрессного пространства
    Состояние
        Свободна (можно аллокировать)
        Зарезервирована
        Fill-on-demand (zero fill)
        Fill-on-demand (text load)
        Commited in memory
        Transitional state (идет Inswapping или Outswapping)
            может быть попытка обратиться на другом процессоре
        Commited Outswapped (лежит на диске)
        Shared
            Copy-on-Write
            Shared memory

    Дополнительные флаги
        Guard Page
            OS генерирует специальный exception при обращении

    Настройки защиты

    Если страница в памяти
        (Это верно для переходных состояний)
        Физическая страница памяти на которую ссылается
    Если страница отсутсвует в памяти
        Mapping
            Fill-on-demand (text load)
                только для based images и PIC-кода (GP-based)
            Mapping to file
                Mapping index
                в самом mappingе
                    Kernel File Handle
                    Start mapping file offset
                    Mapping length

Prototype Page Table

Содержит информацию о прототипных страницах
(Прототипные страницы - страницы используеются более чем одним процессом)
    Основная информация
        А есть ли уже эта страница в памяти
            если есть то ее адресс
        Если нет
            информация о mapping (т.е. как ее достать).

PPD Database

Содержит информацию о физических страницах

Для каждой физической страницы:
    Состояние
        active
        transition
            outswapping
            inswapping
        standby			вывели из состава working set
        modified
        modified no-write       используется FSD для специальных целей
                    например для данных log.
        free			надо заполнять нулями из соображений безопасности
        zeroed
        bad			плохая
                    маркируются страницы физической памяти, вызвавшие проблемы
                    Их удаляют из списка свободных страниц и ставят в специальный список для плохих
                    (пример: Machine Check, ECC error)
        ROM			отмапирована на ROM или ACPI структуры

    Здесь же ведутся списки свободных страниц
    Является ли она залоченой
    Количество отмапирований в виртуальные адрессные пространства
    Список виртуальных адрессов (вместе с пространствами)  куда она отмапирована

THIS SECTION IS UNDER CONSTRUCTION

    Shared memory - где держать mappings?
    Для shared memory нужен список того куда она отмапирована в различных процессах

  Нижнеуровневые интерфейсы работы с памятью Linux:

 UNIX

// linux/mm.h
struct page	// для каждой физической страницы:
{
    page_flags_t	flags;
    atomic_t	_count;		// количество ссылок
    atomic_t	_mapcount;	// сколько раз отмаплена
    unsigned long	private;
    struct address_space* mapping;	// отображение
    pgoff_t		index;          // index в отображении
    struct list_head lru;		// LRU list
    void *		virtual;	// виртуальный адресс страницы
};

struct page*  alloc_pages(unsinged int qfp_mask, unsigned int order)
void*	      page_address(struct page* page)

struct page*  alloc_page(unsigned int qfp_mask)
unsigned long get_free_page(unsigned int qfp_mask)
unsigned long get_zeroed_page(unsigned int qfp_mask)

void free_pages(unsigned long addeess, unsigned int order)
void free_page(unsigned long address)

//	__GFP_WAIT              can pause current process
//	__GFP_HIGH              can use reserved memory
//	__GFP_IO                can use disk I/O
//	__GFP_FS                can use fs I/O
//	__GFP_COLD              use cache cold pages
//	__GFP_NOWARN            no print error message
//
//	__GFP_REPEAT            retry if error
//	__GFP_NOFAIL            retry infinity time
//	__GFP_NORETRY           no retry
//
//	__GFP_NO_GROW
//	__GFP_COMP
//
//	__GFP_DMA               zone
//	__GFP_HIGHMEM		zone
//
//
//	GFP_ATOMIC	__GFP_HIGH
//	GFP_NOIO	__GFP_WAIT
//	GFP_NOFS	(__GFP_WAIT | __GFP_IO)
//	GFP_KERNEL	(__GFP_WAIT | __GFP_IO | __GFP_FS)
//	GFP_USER        (__GFP_WAIT | __GFP_IO | __GFP_FS)
//	GFP_HIGHUSER	(__GFP_WAIT | __GFP_IO | __GFP_FS | _GFP_HIGHMEM)
//	GFP_DMA		__GFP_DMA
//
//	зоны в Linux:
//		ZONE_DMA	< 16M
//		ZONE_NORMAL	16-896MB
//		ZONE_HIGHMEM	> 896MB


81.2.8. МЕХАНИКА СТОЯЩАЯ ЗА ОБРАЩЕНИЯМИ К СТРАНИЦАМ

  Механика стоящая за обращениями к страницам

  Free

    Что происходит при обращении к Free странице?
        Поскольку P: Not present происходит Page Fault CPU exception
        OS анализирует флаги страницы и кидает в процесс exception
        (если сам процесс его не обработает, то процесс будет прерван системой)

  Reserved

    Что происходит при обращении к Reserved странице?
        Тоже самое что и к Free странице
        Разница в том что у Reserved страницы стоит флаг что ее нельзя выделять
        Но для доступа это совсем все равно

  Guard

    Что происходит при обращении к Guard странице?
        Поскольку P: Not present происходит Page Fault CPU exception
        OS анализирует флаги страницы и кидает в процесс exception
        EXCEPTION_GUARD_PAGE
        Для стека процесса система обрабатывает такую ситуацию специальным образом
        наращивая stack.

  Fill-on-demand

    Что происходит при обращении к Fill-on-demand странице?
        Поскольку P: Not present происходит Page Fault CPU exception
        OS анализирует флаги страницы и понимает что она fill-on-demand

        Zero-fill:
        тогда OS берет свободную зануленную страницу (как правило в OS есть
        процесс который поставляет такие страницы)
        ставит ее физический адресс в таблице страниц для нашей виртуальной страницы
        И устанавливает флаг P: Present
        После чего происходит выход из обработчика Page Fault CPU exception
        с перезапуском команды процессора которая вызвала проблему
        (далее читайте сагу про Commit страницу которая в памяти).

        Fill-from-text и Shared memory:
        Это уже memory-mapped files.
        Cмотрим таблицу прототипов
        Если страница для отображении есть в памяти ставим PTE на нее
        Если же нет:
        Система берет свободную страницу физической памяти
        ставит ее физический адресс в таблице страниц для нашей виртуальной страницы
        И устанавливает флаг P: Present
        Затем эта страница лочиться и читается из файла, часть которого отмапирована
        на эту страницу.  После того как чтение закончено и страница разлочена.
        Происходит выход из обработчика Page Fault CPU exception
        с перезапуском команды процессора которая вызвала проблему
        (далее читайте сагу про Commit страницу которая в памяти).

  Commit

    Что происходит при обращении к Commit странице которая в памяти?
        Страница присутсвует в памяти (P: Present)
        Происходит обращение к данным (если конечно позволяют права доступа)
        При загрузке в TLB CPU обновляет флаг A: Accessed
        Если происходит запись в страницу, то CPU обновляет флаг D: Dirty

    Что происходит при обращении к Commit странице которая на диске?
        Система берет свободную страницу физической памяти
        ставит ее физический адресс в таблице страниц для нашей виртуальной страницы
        И устанавливает флаг P: Present
        Затем эта страница лочиться и читается из page-файла,
        (рядом с таблицей страниц есть системная структура - где указано где
        эта страница находится в page-file).
        После того как чтение закончено и страница разлочена.
        Происходит выход из обработчика Page Fault CPU exception
        с перезапуском команды процессора которая вызвала проблему
        (далее читайте сагу про Commit страницу которая в памяти).

  Copy-on-write

    Что происходик при обращении к Copy-on-Write странице (которая присутсвует в памяти)?
        Если чтение то происходит нормальное обращение
        Если запись то поскольку у страницы стоит атрибут R/W: Read only
        то происходит Generic Protection Fault CPU exception
        OS анализирует страницу - узнает что она copy-on-write.
        Берет свободную страницу физической памяти, пересылает не нее исходную
        страницу (это не так просто), mappит copy-on-write страницу на эту
        физическую страницу и ставит аттрибут R/W: Write
        Уменьшает стетчик ссылок у прототипной страницы
        После этого выхожит из обработчика exception c перезапуском
        команды процессора которая вызвала проблему

  Locked

    Что происходит при обращении к Locked странице
        Страница присутсвует в памяти (P: Present)
        Происходит обращение к данным (если конечно позволяют права доступа)
        Если права доступа не позволяют доступ данного типа то происходит
        exception: Generic Protection Fault.

  Вытеснение страницы из памяти

Процессор заполняет в наших страницах флаги:
            A - accessed
            флаг ставиться при загрузке в TLB
        D - dirty

У операционной системы есть нити которые отслеживают состояния этих флагов для
процессов и системы.
Цели:
    1) Узнать какая страница давно не использовалась
    2) Балансировка рабочего набора процесса

    Что происходит при вытеснении страницы из памяти?
        Если страница кода из based образа (код у нас отмаплен из файла),
            ее просто ставят: Not present
            потому что ее можно всегда считать из этого файла
            (поэтому файлы которые запущены на выполнение залочены)
            и отадают в pool свободных физических страниц

        Если страница данных
            Если страница Dirty.
                страницу лочат, записывают в Page file или в mapped file
                сбрасывают флаг Dirty, анлочат
                читаем сразу ниже
            Если страница не Dirty
                она уже есть в page-file
                     или data страница из файла которую еще не модифицировали (Fill-from-text))
                короче ее можно достать тем или иным способом
            Убирают страницу из TLB (INVLDPG)
            Ставят что страница не присутсвует в памяти (P: Not Present)
            и в конечном итоге отдают в pool свободных физических страниц

Что происходет в poolе свободных страниц:
Есть два типа аллокации страницы
    С занулением (из соображений безопасности система не должна отдавать чужие страницы с данными)
    Без зануления (например - если мы все равно будем читать с диска в эту страницу и 100% ее перетрем.
              (или копировать память (COW))

Поэтому как правило есть поток который зануляет сраницы физической памяти.


81.2.8. ДЕЙСТВИЯ ОПЕРАЦИОННОЙ СИСТЕМЫ

  Аллокация памяти

Во первых есть некоторая дробность в выделении регионов памяти, например Windows выделяет
блоками по 64K.

Физическая:
    Запросить блок подходящего размера в списке физических страниц операционной системы

Виртульная сегментная:
    Ищем свободный блок физической памяти нужного размера
    Если его нету, то делаем компактизацию памяти и повторяем операцию
    (Если и на 2й раз не нашли то обламываемся)
    Зануляем этот сегмент

Виртуальная страничная:

    Для процесса:
           (Virtual Address Space)
        Если адресс не указан
            Пройтись по VAD найти свободную зону нужного размера
        Если адресс указан
            Искать свободную зону нужного размера по адрессам
        Если не удалось, то обламываемся.
        Обновляем в VAD - что зона занята
           (Page Allocation)
        Если только RESERVE то законили
        Если COMMIT
            делаем входы в PTE говорящие о том что эта страница пустая
            (Demand Zero PTE).
            (понятно что если нет PT для PDE, то делаем и PT)

    Для отмаппирования в файл
        (Virtual Address Space)
        Если адресс не указан
            Пройтись по VAD найти свободную зону нужного размера
        Если адресс указан
            Искать свободную зону нужного размера по адрессам
        Если не удалось, то обламываемся.
        Обновляем в VAD - что зона занята
        (Page allocation)
        (Имейте в виду объект mappingа уже существует)
        Смотрим объект mappingа
        Если есть prototype pages в prototype page table
        отвечающие этому диапазону то используем их
            увеличиваем счетчик ссылок
        Если нет то
            заводим новые prototypes pages в prototype page table
        Делаем входы в PTE которые prototype и not-present

  Освобождение памяти

    Обычная виртуальная:
       Сверяемся с VAD - можно удалять только регион
       Проходим по PTE
        Если Zero on Demand
            делаем Invalid
        Если Present
            особождаем физическую страницу
            Делаем invalid
        Если в Swap File
            уведомляет swapper, что соответсвующий индекс в
            соответсвующем swap-file теперь свободен
            Делаем invalid
        Если Transitional
            отменяем inswapping/outswapping
            освобождаем физическую страницу
            Делаем invalid
       Освобождаем регион в VAD

THIS SECTION IS UNDER CONSTRUCTION

    Отмапированная в файл:
       В VAD есть флаг - что регион прототипный
       Сверяемся с VAD - можно удалять только регион
       Проходим по PTE
        Если Present
        Если Prototype
        Если Transitional


81.2.9. ОКНА ПАМЯТИ

Собственно память может быть внешней по отношению к адрессному пространству.
В этом случае есть 2 варианта:

    Пересылка блоков памяти (к которым нет прямого доступа)

    Маппирование адрессного пространства (если конечно есть возможность).

Окна могут быть
    физическими   - когда мапируется физическая память
    виртуальными  - когда мапируется виртуальное адрессное пространство

    Окна памяти
        EMS
        PAE
        Маппирование файлов в память

    Память с отсутвием прямого доступа
        XMS

    Memory mapper
        Вызовы между страницами

  DOS EMS

 MS-DOS

--------m-6740-------------------------------
INT 67 - LIM EMS - GET MANAGER STATUS
    AH = 40h
Return: AH = status (00h,80h,81h,84h) (see #03648)
Note:	this call can be used only after establishing that the EMS driver is in
      fact present
SeeAlso: AH=3Fh,AX=FFA5h,@xxxxh:xxxxh"PMM"

(Table 03648)
Values for EMS function status:
 00h	successful
 80h	internal error
 81h	hardware malfunction
 82h	busy -- retry later
 83h	invalid handle
 84h	undefined function requested by application
 85h	no more handles available
 86h	error in save or restore of mapping context
 87h	insufficient memory pages in system
 88h	insufficient memory pages available
 89h	zero pages requested
 8Ah	invalid logical page number encountered
 8Bh	invalid physical page number encountered
 8Ch	page-mapping hardware state save area is full
 8Dh	save of mapping context failed
 8Eh	restore of mapping context failed
 8Fh	undefined subfunction
 90h	undefined attribute type
 91h	feature not supported
 92h	successful, but a portion of the source region has been overwritten
 93h	length of source or destination region exceeds length of region
      allocated to either source or destination handle
 94h	conventional and expanded memory regions overlap
 95h	offset within logical page exceeds size of logical page
 96h	region length exceeds 1M
 97h	source and destination EMS regions have same handle and overlap
 98h	memory source or destination type undefined
 9Ah	specified alternate map register or DMA register set not supported
 9Bh	all alternate map register or DMA register sets currently allocated
 9Ch	alternate map register or DMA register sets not supported
 9Dh	undefined or unallocated alternate map register or DMA register set
 9Eh	dedicated DMA channels not supported
 9Fh	specified dedicated DMA channel not supported
 A0h	no such handle name
 A1h	a handle found had no name, or duplicate handle name
 A2h	attempted to wrap around 1M conventional address space
 A3h	source array corrupted
 A4h	operating system denied access
--------m-6741-------------------------------
INT 67 - LIM EMS - GET PAGE FRAME SEGMENT
    AH = 41h
Return: AH = status (see also AH=40h)
        00h function successful
        BX = segment of page frame
SeeAlso: AH=58h,AH=68h
--------m-6742-------------------------------
INT 67 - LIM EMS - GET NUMBER OF PAGES
    AH = 42h
Return: AH = status (see also AH=40h)
        00h function successful
        BX = number of unallocated pages
        DX = total number of pages
BUG:	DOS 6.0 EMM386.EXE causes a system lock-up or reboot if in AUTO mode
      when this call is made; use AH=46h to ensure that EMM386 is ON
      before making this call
SeeAlso: INT 2F/AX=2702h
--------m-6743-------------------------------
INT 67 - LIM EMS - GET HANDLE AND ALLOCATE MEMORY
    AH = 43h
    BX = number of logical pages to allocate
Return: AH = status (00h,80h,81h,84h,85h,87h,88h,89h) (see #03648)
    DX = handle if AH=00h
SeeAlso: AH=45h
--------m-6744-------------------------------
INT 67 - LIM EMS - MAP MEMORY
    AH = 44h
    AL = physical page number (0-3)
    BX = logical page number
        or FFFFh to unmap (QEMM)
    DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Ah,8Bh) (see #03648)
SeeAlso: AH=69h
--------m-6745-------------------------------
INT 67 - LIM EMS - RELEASE HANDLE AND MEMORY
    AH = 45h
    DX = EMM handle
Return: AH = status (00h,80h,81h,83h,84h,86h) (see #03648)
SeeAlso: AH=43h
--------m-6751-------------------------------
INT 67 - LIM EMS 4.0 - REALLOCATE PAGES
    AH = 51h
    DX = handle
    BX = number of pages to be allocated to handle
Return: AH = status (00h,80h,81h,83h,84h,87h,88h) (see #03650)
    BX = actual number of pages allocated to handle

(Table 03650)
Values for EMS function status:
 00h	successful
 80h	internal error
 81h	hardware malfunction
 83h	invalid handle
 84h	undefined function requested
 87h	more pages requested than present in system
 88h	more pages requested than currently available
 8Ah	invalid logical page number encountered
 8Bh	invalid physical page number encountered
 8Fh	undefined subfunction
 90h	undefined attribute type
 91h	feature not supported
 A0h	no such handle name
 A1h	duplicate handle name
--------m-6755-------------------------------
INT 67 - LIM EMS 4.0 - ALTER PAGE MAP AND JUMP
    AH = 55h
    AL = subfunction
        00h physical page numbers provided by caller
        01h segment addresses provided by caller
    DX = handle
    DS:SI -> structure containing map and jump address
Return: (at target address unless error)
    AH = status (00h,80h,81h,83h,84h,8Ah,8Bh,8Fh) (see #03648)
SeeAlso: AH=56h
--------m-6756-------------------------------
INT 67 - LIM EMS 4.0 - ALTER PAGE MAP AND CALL
    AH = 56h
    AL = subfunction
        00h physical page numbers provided by caller
        DX = handle
        DS:SI -> structure containing page map and call address
        01h segment addresses provided by caller
        DX = handle
        DS:SI -> structure containing page map and call address
        02h get page map stack space required
        Return: BX = stack space required
Return: (if successful, the target address is called.  Use a RETF to return
     and restore mapping context)
    AH = status (00h,80h,81h,83h,84h,8Ah,8Bh,8Fh) (see #03648)
SeeAlso: AH=55h
--------m-6757-------------------------------
INT 67 - LIM EMS 4.0 - MOVE/EXCHANGE MEMORY REGION
    AH = 57h
    AL = subfunction
        00h move memory region
        01h exchange memory region
    DS:SI -> structure describing source and destination (see #03653)
Return: AH = status (see #03652)
Note:	source and destination may overlap for a move, in which case the copy
      direction is chosen such that the destination receives an intact copy
      of the source region

(Table 03652)
Values for EMS function status:
 00h	successful
 80h	internal error
 81h	hardware failure
 83h	invalid handle
 84h	undefined function requested
 8Ah	invalid logical page number encountered
 8Fh	undefined subfunction
 92h	successful, but a portion of the source region has been overwritten
 93h	length of source or destination region exceeds length of region
      allocated to either source or destination handle
 94h	conventional and expanded memory regions overlap
 95h	offset within logical page exceeds size of logical page
 96h	region length exceeds 1M
 97h	source and destination EMS regions have same handle and overlap
 98h	memory source or destination type undefined
 A2h	attempted to wrap around 1M conventional address space

Format of EMS copy data:
Offset	Size	Description	(Table 03653)
 00h	DWORD	region length in bytes
 04h	BYTE	source memory type
        00h conventional
        01h expanded
 05h	WORD	source handle (0000h if conventional memory)
 07h	WORD	source initial offset (within page if EMS, segment if convent)
 09h	WORD	source initial segment (conv mem) or logical page (EMS)
 0Bh	BYTE	destination memory type
        00h conventional
        01h expanded
 0Ch	WORD	destination handle
 0Eh	WORD	destination initial offset
 10h	WORD	destination initial segment or page

  Windows AWE

Имейте в виду что для аллокации региона адрессного пространства который будет mappиться
используют  VirtualAlloc(MEM_PHYSICAL)

 Windows

BOOL WINAPI AllocateUserPhysicalPages(
  __in     HANDLE hProcess,
  __inout  PULONG_PTR NumberOfPages,
  __out    PULONG_PTR UserPfnArray
);

BOOL WINAPI AllocateUserPhysicalPagesNuma(
  __in     HANDLE hProcess,
  __inout  PULONG_PTR NumberOfPages,
  __out    PULONG_PTR PageArray,
  __in     DWORD nndPreferred
);

BOOL WINAPI FreeUserPhysicalPages(
  __in     HANDLE hProcess,
  __inout  PULONG_PTR NumberOfPages,
  __in     PULONG_PTR UserPfnArray
);

BOOL WINAPI MapUserPhysicalPages(
  __in  PVOID lpAddress,
  __in  ULONG_PTR NumberOfPages,
  __in  PULONG_PTR UserPfnArray
);

BOOL WINAPI MapUserPhysicalPagesScatter(
  __in  PVOID *VirtualAddresses,
  __in  ULONG_PTR NumberOfPages,
  __in  PULONG_PTR PageArray
);

  Переходы внутри окна

    CALL MAPPER
    JMP  MAPPER
    RET  MAPPER

    {SPACE, ADDRESS}

  Оверлеи

Что делать кода код не входит в адрессное пространство?
(Сейчас это практически нереально, но во времена DOS было сплошь и рядом).

    CALL OVERLAY
    JMP  OVERLAY
    RET  OVERLAY

  Доступ к данным другого процесса Windows

Это пример когда память совершенно перпендикулярна
(ее нельзя отмаппить, но можно пересылать).

Требуется для отладки.

 Windows

BOOL WINAPI ReadProcessMemory(
  __in   HANDLE hProcess,
  __in   LPCVOID lpBaseAddress,
  __out  LPVOID lpBuffer,
  __in   SIZE_T nSize,
  __out  SIZE_T *lpNumberOfBytesRead
);

BOOL WINAPI WriteProcessMemory(
  __in   HANDLE hProcess,
  __in   LPVOID lpBaseAddress,
  __in   LPCVOID lpBuffer,
  __in   SIZE_T nSize,
  __out  SIZE_T *lpNumberOfBytesWritten
);


81.2.10. RTL ДЛЯ ПАМЯТИ

THIS SECTION IS UNDER CONSTRUCTION

TODO:
    Получение памяти в pool
        BIOS
        Win32
        UNIX
        обычная политика:
        мелкий блок из списков кучи, если больше размеров страницы,
        то используем целую страницу.

        Списки с блоками разного размера
        Деление на 2
    соответственно фрагментация и дефрагментация кучи.

    Использование slab аллокаторов

    Выделение выровненного буфера
        как правило требуется для системных операций

    Более сложные варианты
        Smart pointers
        Garbage collection

Концептуальный RTL для памяти

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

    Физической
        Структуры для памяти
            Список
            Сложные стратегии
        Аллокировать блок память
        Деаллокировать блок память
        Переаллокировть блок памяти
        Стратегия выделения
            First fit, Best fit, Last fit
                        особенно полезен

    Кучи
        Создать кучу
        Добавить блок в кучу
        Удалить блок из кучи
        callback если нет места
        Компактизация кучи
        Локирование/Анлокирование кучи в памяти (если виртуальная)
        Узнать
            размер кучи
            размер свободной памяти в куче
            размер максимального свободного блока

    RTL языков
        new  		простой
        new[]		с доп структурой

    Общий RTL
        Аллокировать память с указанным выравниванием

    Виртуальной
        Выделить станицы виртуальной памяти
            по указанному виртуальному адрессу
            все равно где
        Удалить страницы виртуальной памяти

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

        Залочить страницы в памяти
        Анлочить страницы в памяти
            квоты процесса на залоченную память

        Изменить параметры защиты страниц
            Чтение
            Запись
            Выполнение

        все тоже самое но для другого процесса

        Аллокировать разделяемую память (будет шариться между процессами)
            то же но именованную

    Когда физическое пространство меньше виртуального или
    память находиться сбоку - например EMS.
        Аллокировать блок
        Деаллокировать блок
        Помаппить блок в адрессное пространство
        Узнать помапплен ли блок

    Ядра (Paged, Non-paged, kernel/user space)
        квоты процесса на залоченную память

        аллокировать физическую память и помапить ее
            идущую подряд
        аллокировать физическую память в специальном регионе
            например нижние 16M или 4G
                из за ISA/PCI устройств
        аллокировать paged/non-paged память
            идущую подряд

        аллокировать некэшируемую память

        аллокировать память немедленно  и успешно (для ISR итд)

        копировать из/в пользовательское адрессное пространство


81.3. ФАЙЛОВАЯ И STORAGE ПОДСИСТЕМА

Основные компоненты:

OS API - API предоставляемые OS для работы с файлами и файловыми системами.

VFS Layer - осуществляет примитивы и мультиплексирует доступ к нижележащим FSD

Cache Manager - осуществляет управление виртульным кэшированием
(как правило сильно завязан на Memory Manager)

Virtual Cache - кэш кэширующий блоки файлов (бывает и других объектов)

Filesystem Filter Driver - драйвер сидящей выше файловой системы и перехватывающий
запросы к ней.
Основные типичные варианты:
Реализация обслуживания Reparse Points
статистика
CDP

Filesystem Driver - драйвер который собственно осуществляет работу с файловой системой

Block Device Filter - фильтр блочного устройства

Logical Disk Layer

Software RAID Layer

посмотрите секцию 55.10.0

Partitioning layer

Physical disk layer

Disk Scheduler

посмотрите секцию 55.10 подсекцию "Неупорядоченное выполнение"

Physical Cache

SCSIlizer

SCSI Controller driver

THIS SECTION IS UNDER CONSTRUCTION


81.3.1. STORAGE УСТРОЙСТВА

  Классы устройств хранения данных

Жесткий диск (Fixed)

Removable диск

Оптический накопитель

Ленточный накопитель

Media changer (Jukebox)

  Интерфейсы storage устройств

  Низкоуровневые интерфейсы

Старые низкоуровневые интерфейсы:
    FDC - floppy disk controller
    MFM - disk controller
    RLL - disk controller
    ESDI - disk controller

  Среднеуровневые интерфейсы

Среднеуровневые интерфейсы:
    IDE - interllectual drive electronics
           он же ATA (AT-attachment)
    SATA - serial ATA

  Высокоуровневые интерфейсы

Высокоуровневые интерфейсы
(Используют SCSI комманды)
    ATAPI - ATA packet interface
    SCSI  - Small computer system interface
    SAS   - Serial attached SCSI
    FC    - Fibrechannel

и также storage devices на интерфейсах
    USB   - Universal Serial Bus
    Firewire


81.3.1.1. СТРУКТУРА ДИСКОВЫХ НОСИТЕЛЕЙ

THIS SECTION IS UNDER CONSTRUCTION

  Геометрия

  Адрессация

Для низкоуровневых и ранних среднеуровневых интерфейсов характерна CHS
адресация, для высокоуровневых - LBA адрессация.

  Выравнивание по физическому сектору

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

Обращение к выровненному адрессу:

Обращение к невыровненному адрессу:

  Физический сектор - IDE/SATA

Как узнать что у нас физический сектор отличается от логического?

IDE IDENTIFY DEVICE - COMMAND
----------------------------------------------------------------------------
Word	Description
----------------------------------------------------------------------------
106	Physical sector size/Logical sector size (Optional)	   (ATA8)
        Bit	Description
        15	Shall be 0
        14	Shall be 1
        13	1 = device have multiple log. sector/physical sector
        12	1 = device logical sector longer that 256 words
        3..0	2^X logical sectors per physical sector
----------------------------------------------------------------------------
209	 Alignment of logical blocks within a physical block (Optional) (ATA8)
         15      Shall be 0
        14	Shall be 1
        13..0	Logical sector offset within first physical
            sector, where first logical sector is placed
----------------------------------------------------------------------------

  Выравнивание партиций

  Sector Offset


81.3.1.2. ТИПОВЫЕ КОМАНДЫ STORAGE DEVICES

THIS SECTION IS UNDER CONSTRUCTION

Низкоуровневые интерфейсы мы сейчас рассматривать не будем
(хотя это очень интересно)

  IDE

Основные команды (для не-ATAPI дисковых устройств):

--------------------------------------------------
Execute Drive Diagnostic
Format Track
Identify Device
Idle
Nop
Read Buffer
Read DMA
Read Long
Read Multiple
Read Sectors
Read Verify Sectors
Read DMA Queued
Recalibrate
Seek
Set Features
Write Buffer
Write DMA
Write Long
Write Multiple
Write Same
Write Sectors
Write Verify
Write DMA Queued
Flush Cache
--------------------------------------------------

так же есть Extended формы для поддержки LBA48 итд

  SCSI

Основные команды (для дисковых устройств):

--------------------------------------------------
Test Unit Ready
Request Sense
Format Unit
Read
Write
Inquiry
Verify
Mode Sense
Mode Select
Reserve Unit
Release Unit
Start/Stop Unit
Prevent/Allow Media Removal
Read Capacity
Read Format Capacities
--------------------------------------------------

  Общие команды

PREVENT/ALLOW MEDIA REMOVAL
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (1Eh)              |
+----+----+----+----+----+----+----+----+
|      LUN     |           ...          |
+----+----+----+----+----+----+----+----+
|                 .....                 |
+--                                   --+
|                 .....                 |
+----+----+----+----+----+----+----+----+
|                ...               |Prev|
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

START/STOP UNIT
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (1Bh)              |
+----+----+----+----+----+----+----+----+
|      LUN     |        ...        | Imm|
+----+----+----+----+----+----+----+----+
|                 .....                 |
+--                                   --+
|                 .....                 |
+----+----+----+----+----+----+----+----+
|             ...             |LoEj|Strt|
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

Для SCSI используем команду READ CAPACITY с флагом PMI (Physical Media Information).

READ CAPACITY (10)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (25h)              |
+----+----+----+----+----+----+----+----+
|      LUN     |        ...        |RAdr|
+----+----+----+----+----+----+----+----+
|                  LBA                  |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|                 .....                 |
+--                                   --+
|                 .....                 |
+----+----+----+----+----+----+----+----+
|                ...               | PMI|
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

typedef struct _READ_CAPACITY_DATA
{
        ULONG LogicalBlockAddress;
        ULONG BytesPerBlock;
} READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;

READ CAPACITY(16)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (9Eh)              |
+----+----+----+----+----+----+----+----+
|              |           10h          |
+----+----+----+----+----+----+----+----+
|MSB                                    |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
|                  LBA                  |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                   LSB |
+----+----+----+----+----+----+----+----+
|                                       |
+--          Allocation Len           --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|     ...                          |PMI |
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

typedef struct _READ_CAPACITY_DATA16
{
    QWORD LogicalBlockAddress;
        ULONG BytesPerBlock;
        BYTE  Flags;
        BYTE  Reserved[19];
} READ_CAPACITY_DATA16, *PREAD_CAPACITY_DATA16;

  Ввод/Вывод

Command	  LBA   Len
READ(6)	  21	8
READ(10)  32	16
READ(12)  32	32
READ(16)  64    32

READ (6)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (08h)              |
+----+----+----+----+----+----+----+----+
|      LUN     |       LBA (high)       |
+----+----+----+----+----+----+----+----+
|               LBA (low)               |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|             Transfer len              |
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

READ (10)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (28h)              |
+----+----+----+----+----+----+----+----+
|      LUN     | PPO| FUA|   ...   |RAdr|
+----+----+----+----+----+----+----+----+
|                  LBA                  |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|                 .....                 |
+----+----+----+----+----+----+----+----+
|             Transfer len              |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

    READ(16)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (88h)              |
+----+----+----+----+----+----+----+----+
|   RDPROTECT  |DPO |FUA |... | Imm|RAdr|
+----+----+----+----+----+----+----+----+
|MSB                                    |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--		  LBA                 --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                   LSB |
+----+----+----+----+----+----+----+----+
|         Prefetch len (blocks)         |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|     ...      |  Group Number          |
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

Command	  LBA   Len
WRITE(6)   21	8
WRITE(10)  32	16
WRITE(12)  32   32
WRITE(16)  64   32

WRITE (6)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (0Ah)              |
+----+----+----+----+----+----+----+----+
|      LUN     |       LBA (high)       |
+----+----+----+----+----+----+----+----+
|               LBA (low)               |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|             Transfer len              |
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

WRITE (10)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (2Ah)              |
+----+----+----+----+----+----+----+----+
|      LUN     | DPO| FUA|   ...   |RAdr|
+----+----+----+----+----+----+----+----+
|                  LBA                  |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|                 .....                 |
+----+----+----+----+----+----+----+----+
|             Transfer len              |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

WRITE(16)
  7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+
|             Opcode (8Ah)              |
+----+----+----+----+----+----+----+----+
|  WRPROTECT   | DPO|FUA |    |FNV |    |
+----+----+----+----+----+----+----+----+
|MSB                                    |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--		  LBA                 --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                   LSB |
+----+----+----+----+----+----+----+----+
|                                       |
+--          Verification Len         --+
|                                       |
+--                                   --+
|                                       |
+--                                   --+
|                                       |
+----+----+----+----+----+----+----+----+
|     ...      |   Group Number         |
+----+----+----+----+----+----+----+----+
|                Control                |
+----+----+----+----+----+----+----+----+

  Работа с cache

  Низкоуровневое форматирование

  Удобные опциональные команды


81.3.1.3. СПЕЦИАЛЬНЫЕ FEATURES НА КОТОРЫЕ НАДО ОБРАТИТЬ ОСОБОЕ ВНИМАНИЕ

  Внеочередное выполнение

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

Изначально это было свойство SCSI, но современные SATA диски тоже это поддерживают
(но не все модели и только с правильными контроллерами).

  Перекрестные команды

Предположим, что нам надо скопировать данные на другое устройство.

В обычном случае это сводиться к тому, что данные надо прочитать
из одного устройства и записать в другое. Что долго (2 трансфера по шине)
и плюс к этому нагружает Host.

Перекрестная команда - Например Copy - дается одному из устройств и содержит в
себе как параметер команду другому устройству, которую первое устройство выдает
на шину. В результате идет прямой трансфер по шине и Освобождает Host controller
от загрузки данными.

Типовой пример для таких команд - например копирование данных CD с одного устройства
на другое, или репликация диска.

К сожалению в настоящее время перекрестные команды стали уходить. Их поддерживает SCSI,
но уже на SAS например ничего хорошего не сделаешь потому что шина не общая.
Остается FC.

Другие подобные команды

  Блокировка

С помощью SCSI команд:

    RESERVE UNIT
    RELEASE UNIT

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

Например в кластерах (Windows) диск на котором храниться кворум локирован одной из нод
кластера. Поэтому когда происходит failover, другая нода дает команду RELEASE UNIT
от имени той ноды которая была его владельцем, поэтому в кластерах используются
мультиинициатроные контроллеры.

  Кэширование на уровне устройства

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

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

    ADD LBA TO NV CACHE PINNED SET
        FLUSH NV CACHE
    NV CACHE DISABLE
    NV CACHE ENABLE
    QUERY NV CACHE MISSES
    QUERY NV CACHE PINNED SET
    REMOVE LBA FROM NV CACHE PINNED SET
    RETURN FROM NV CACHE POWER MODE
    SET NV CACHE POWER MODE

  Поддержка RAID массивов

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

    XDREAD
    XDWRITE
    XDWRITEREAD
    XPWRITE
    ORWRITE

Write and Update Parity:

Regenerate:

Rebuild:

  SSD

При работе с Solid State Disk один из главных факторов тормозящих
работу - это стирание.

В начале диск пустой - и все записи быстрые (так как не надо стирать).

Потом начинают появляться блоки которые надо стирать, а это долго.

Если блок перестает использоваться файловой системой накопитель этого
просто не знает. И не может стереть его в background, продолжает его
хранить.

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


81.3.1.4. ДРАЙВЕРА STORAGE CONTROLLERS

Практически типовые запросы к SCSI controllers сводяться к:
    - Инициализация адаптера (ну и поиск тоже)
    - Сброс Шины
    - Выполнение SCSI команды
    остальное это практически support для работы с оборудованием

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

Просто подавляюшее большенство storage controllers - Bus Master и им нужны
Физические, а не виртуальные адреса буферов.
Также есть вариант когда передаются виртуальные, а драйвер контроллера с помощью
системных RTL их транслирует в физические, что удобно для Scater/Gather, потому что
уменьшается буферизация.

Но самая большая засада, когда Storage controller расчитан на предидущую архитектуру.
Например ISA Bus Master SCSI - не может адресовать более 16MB памяти,
32-bit PCI Bus Master SCSI - не может вылезти за границу 4GB.
В таких случаях приходиться идти на ухищрения типа выделения памяти в младшей зоне
и переброска через нее. Или дополнительная поддержка чипсетом верхних DMA страниц для
конкретного PCI слота, ну и OSю конечно.

  SCSI

  SCSI Miniport Driver (Windows)

Внизу список функций которые экспортирут SCSI Miniport:

HwScsiInitialize()
    инициализует HBA
    (по возможности следует воздержаться от сброса SCSI шины,
     так как ее и так сбросили RESETом).

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

HwScsiResetBus()
    Сбрасывает указанную SCSI шину
        (У адаптера могут быть несколько шин)

HwScsiStartIo()
    Передает SCSI_REQUEST_BLOCK, который содержит SCSI команду для
    выполнения. Кроме команды SCSI_REQUEST_BLOCK содержит всю адрессную
    информацию о том какое именно устройство, а также место куда записываются
    результат выполнения команды, и SCSI Sense.

    typedef struct _SCSI_REQUEST_BLOCK
    {
        USHORT  Length;
        UCHAR  Function;
        UCHAR  SrbStatus;
        UCHAR  ScsiStatus;
        UCHAR  PathId;
        UCHAR  TargetId;
        UCHAR  Lun;
        UCHAR  QueueTag;
        UCHAR  QueueAction;
        UCHAR  CdbLength;
        UCHAR  SenseInfoBufferLength;
        ULONG  SrbFlags;
        ULONG  DataTransferLength;
        ULONG  TimeOutValue;
        PVOID  DataBuffer;
        PVOID  SenseInfoBuffer;
        struct _SCSI_REQUEST_BLOCK  *NextSrb;
        PVOID  OriginalRequest;
        PVOID  SrbExtension;
        union
        {
            ULONG  InternalStatus;
            ULONG  QueueSortKey;
        };
        UCHAR  Cdb[16];
    } SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;

HwScsiAdapterControl()
    Осуществляет управление адаптером
    Возможные типы controls:
        ScsiQuerySupportedControlTypes
        ScsiStopAdapter
        ScsiRestartAdapter
        ScsiSetBiosConfig - востановка настроек которые нужны BIOS для Reboot
        ScsiSetRunningConfig

HwScsiAdapterState()
    Сохраняет или востанавливает состояние SCSI HBA
    (Надо если BIOS его уже проиницилизировал)

HwScsiInterrupt()
    Точка куда приходят аппаратные прерывания от адаптера

HwScsiEnableInterruptsCallback()
HwScsiDisabledInterruptsCallback()
    вспомогательные функции которые вызываются через систему из
    HwScsiInterrupt() с целью разбить обработку на top and bottom half.

HwScsiDmaStarted()
    Вызывается если HBA - Slave DMA, после того как OS настроит DMA Transfer.

HwScsiTimer()
    Приходят нотификации от таймера

остальные внешние функции связаны с WMI, и для нас непринципиальны.

  Linux 2.6.27.9.

Собственно имеем то же самое - обязательные функции:
    - выполнить команду
    - сброс шины (device/target/bus/host)
и куча  optional функций для различных случаев (Linux - это базар, поэтому это
обычная ситуация).

struct scsi_host_template {
    struct module *module;
    const char *name;

    int (* detect)(struct scsi_host_template *);	// OBSOLETE
    int (* release)(struct Scsi_Host *);		// OBSOLETE
    const char *(* info)(struct Scsi_Host *);			   // OPTIONAL
    int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg); // OPTIONAL
    int (* compat_ioctl)(struct scsi_device *dev, int cmd, void __user *arg); // OPTIONAL

    int (* queuecommand)(struct scsi_cmnd *,
                 void (*done)(struct scsi_cmnd *));
    Основная функция с помощью которой дают команду.

    int (* transfer_response)(struct scsi_cmnd *,
                  void (*done)(struct scsi_cmnd *));

    int (* eh_abort_handler)(struct scsi_cmnd *);
    int (* eh_device_reset_handler)(struct scsi_cmnd *);
    int (* eh_target_reset_handler)(struct scsi_cmnd *);
    int (* eh_bus_reset_handler)(struct scsi_cmnd *);
    int (* eh_host_reset_handler)(struct scsi_cmnd *);

    int (* slave_alloc)(struct scsi_device *);	// OPTIONAL
    int (* slave_configure)(struct scsi_device *);  // OPTIONAL
    void (* slave_destroy)(struct scsi_device *);	// OPTIONAL
    int (* target_alloc)(struct scsi_target *);	// OPTIONAL
    void (* target_destroy)(struct scsi_target *);	// OPTIONAL
    int (* scan_finished)(struct Scsi_Host *, unsigned long); 	// OPTIONAL
    void (* scan_start)(struct Scsi_Host *);			// OPTIONAL
    int (* change_queue_depth)(struct scsi_device *, int); 		// OPTIONAL
    int (* change_queue_type)(struct scsi_device *, int);		// OPTIONAL
    int (* bios_param)(struct scsi_device *, struct block_device *,
            sector_t, int []);               		// OPTIONAL
    int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
                                    // OPTIONAL
    enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); // OPTIONAL

    const char *proc_name;	// Name of proc directory
    struct proc_dir_entry *proc_dir;
    int can_queue;
    int this_id;
    unsigned short sg_tablesize;
    unsigned short max_sectors;
    unsigned long dma_boundary;
    short cmd_per_lun;
    unsigned char present;
    unsigned supported_mode:2;
    unsigned unchecked_isa_dma:1;
    unsigned use_clustering:1;
    unsigned emulated:1;		// ATAPI for example
    unsigned skip_settle_delay:1;
    unsigned ordered_tag:1;
    unsigned int max_host_blocked;
    struct device_attribute **shost_attrs;
    struct device_attribute **sdev_attrs;
    struct list_head legacy_hosts;
};

struct scsi_cmnd {
    struct scsi_device *device;
    struct list_head list;  	/* scsi_cmnd participates in queue lists */
    struct list_head eh_entry; 	/* entry for the host eh_cmd_q */
    int eh_eflags;			/* Used by error handlr */

    unsigned long serial_number;
    unsigned long jiffies_at_alloc;

    int retries;
    int allowed;
    int timeout_per_command;

    unsigned char prot_op;
    unsigned char prot_type;

    unsigned short cmd_len;
    enum dma_data_direction sc_data_direction;
    unsigned char *cmnd;
    struct timer_list eh_timeout;	/* Used to time out the command. */
    struct scsi_data_buffer sdb;
    struct scsi_data_buffer *prot_sdb;
    unsigned underflow;
    unsigned transfersize;
    struct request *request;	/* The command we are  working on */
    unsigned char *sense_buffer;
    void (*scsi_done) (struct scsi_cmnd *);	// Callback

    // -- Host specific fields
    struct scsi_pointer SCp;	/* Scratchpad used by some host adapters */
    unsigned char *host_scribble;
    int result;		/* Status code from lower level driver */
    unsigned char tag;	/* SCSI-II queued command tag */
};

  IDE

  ATA Miniport Driver (Windows)

DriverEntry()
    Entry point для драйвера

AtaAdapterControl()
    Вызывается для PnP и Power management
        IdeStart
        IdeStop
        IdePowerUp
        IdePowerDown

AtaControllerChannelEnabled()
    Разрешает/запрещает канал

AtaControllerTransferModeSelect()
    Устанавливает режим передачи

AtaChannelInitialize()
    Инициализирует канал

AtaHwInitialize()

AtaHwBuildIo()
    передается IDE_REQUEST_BLOCK, в нем ставяться необходимые

AtaHwStartIo()
    передается IDE_REQUEST_BLOCK с командой которую надо выполнить

    typedef struct _IDE_REQUEST_BLOCK
    {
        USHORT  Function;
        UCHAR  IrbStatus;
        UCHAR  AtaStatus;
        UCHAR  AtaError;
        UCHAR  Channel;
        UCHAR  TargetId;
        UCHAR  Lun;
        UCHAR  CdbLength;
        UCHAR  SenseInfoBufferLength;
        UCHAR  SenseInfoBufferType;
        UCHAR  QueueTag;
        ULONG  ReservedAsUlong;
        USHORT  IrbFlags;
        ULONG  TimeOutValue;
        ULONG  DataTransferLength;
        PVOID  IrbExtension;
        PVOID  DataBuffer;
        PVOID  SenseInfoBuffer;
        PVOID  NextIrb;
        PVOID  Reserved;
        union
        {
            IDE_TASK_FILE  IdeTaskFile;
            UCHAR  Cdb[16];
            POWER_CHANGE_INFO  PowerChange;
            UCHAR  AsUChar[16];
        };

    } IDE_REQUEST_BLOCK, *PIDE_REQUEST_BLOCK;

AtaHwInterrupt()
    вызывается при аппаратном прерывании

AtaHwReset()
    сброс шины

AtaHwChannelControl()
    управление Pnp и Power
        StartChannel
        StopChannel
        PowerUpChannel
        PowerDownChannel


81.3.1.5. ФИЛЬТРЫ STORAGE CONTROLLER ДРАЙВЕРОВ

THIS SECTION IS UNDER CONSTRUCTION

Собственно фильтры Storage Controller drivers перехватывают запросы
идущие к storage controllers drivers.

Существует два основных практических использования данных фильтров:
    Sniffering
    Firewall

  Sniffering

   Когда логируются все запросы к устройству (что позволяет проанализировать
   что же с этим устройством делали).

  Firewall

   Блокирование определенных типов запросов
   Например - не давать писать, или проигрывать CD.


81.3.1.6. SCSILIZER

THIS SECTION IS UNDER CONSTRUCTION

SCSILizer - компонент, как правило встроенный в систему который преобразует
типовые запросы на ввод/вывод операционной системы в SCSI команды.

Например в Windows эту роль выполняет драйвер класса диска.

Например типичный запрос на чтение операционной системы содержит:
    - Block Device offset  (в байтах, как правило 64бита)
    - Transfer Length (как правило тоже в байтах, обычно 32-бита).

а устройству идет запрос
    - Начальный номер блока
    - Количество блоков

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

Кроме того, SCSIlizerу приходиться разбивать запросы.
Так как SCSI например у SCSI READ(10) Transfer Len в блоках = 2 байта, и если читать
больше 16K блоков за раз, то запрос не влезет в одну SCSI команду.

Более того - у контроллеров есть ограничения (особенно для IDE) по количеству блоков
которые можно передать за одну команду.

Со SCSIlizeroм связаны и другие неприятные вещи:
Например - у вас есть диск емкостью 5TB, с размером сектора 512 байт (LBA > 2^32),
например SAS, есть контроллер, который поддерживает 16-байтовые SCSI команды,
есть дрйвер к нему, который понимает 16-байтовые команды,
но операционная система у Вас - Windows 2003 Server (не R2), у нее SCSILizer не
генерирует команды для LBA > 2^32, поэтому вы увидите диск 2TB, а не 5TB.

Что нужно для поддержки LBA > 32bit на SCSI:
    - Устройство с таким LBA
    - Контроллер который понимает 16-байтовые SCSI команды
    - Драйвер к нему который понимает 16-байтовые SCSI команды.
    - Операционная система содержащая правильный SCSILizer который готов
      работать с большими SCSI дисками.

Примерно такая же ситуация как со SCSI существует с IDE.
Например в Windows есть ATA Port, который осуществляет трансляцию системных
запросов на ввод/вывод в IDE_REQUEST_BLOCKs, которые он же и выдает на выполнение
ATA минипортам.


81.3.1.7. DISK SCHEDULING

THIS SECTION IS UNDER CONSTRUCTION

Читайте секцию 55.10, раздел "Неупорядоченное выполнение".

Кроме того, современный Disk Scheduling может учитывать возможности Storage по
неупорядоченному выполнению команд (смотри секцию 81.3.1.3).


81.3.1.8. ФИЗИЧЕСКОЕ КЭШИРОВАНИЕ

THIS SECTION IS UNDER CONSTRUCTION

Кэширование поднимает производительность.
Физическое кэширование - кэширование блоков дискового устройства.

Если данные для чтения есть в cache - их можно взять оттуда.
Это быстро (доступ к диску длинная операция).

Если данных для чтения нету, то их можно считать с диска и
занести в cache (вдруг еще понадобиться).

Write - еще более спекулятивная операция, потому что можно бросить
данные в cache и вернуть ok.

Переодически идут запросы на сброс данных из cache:

Возможны также разные политики: Write-through и Write-back.
Кроме того некоторые запросы могут быть отмаркированы что бы не
использовать cache.


81.3.1.8.1. MULTIPATH I/O

THIS SECTION IS UNDER CONSTRUCTION

В современных системах (например FC) возможны ситуации когда дисковое
устройство или массив доступны более чем по одному пути.
Например через разные контроллеры.

Уровень Multipath I/O разделяет эти запросы по путям увеличвая таким
образом производительность.

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


81.3.1.9. УРОВЕНЬ ФИЗИЧЕСКОГО ДИСКА

THIS SECTION IS UNDER CONSTRUCTION

На этом уровне в операционной системе появляются блочные устройства.
Потому что ниже находятся только устройства с конкретным интерфейсом (например IDE)

Как правило здесь же происходит разделение устройств по классам
    - Hard disk
    - CD/DVD etc
    - Tape

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

    Чтение/запись
        транслируется через SCSILizer, формируется запрос зависимый
        от storage среды и отправляется на более нижний уровень.
        или запрос отправляется драйверу блочного устройства
        Кроме того для I/O операций также формируются и выполняются
        дополнительные команды типа:
            TEST UNIT READY
            START/STOP UNIT
            PREVENT/ALLOW MEDIA REMOVAL

    Поддержка pass-through
        что позволяет пробрасывать команды специфичные для storage controller
        непосредственно через блочное устройство

    Поддержка специфических IOCTL для media
        вообще для storage device
            IOCTL_STORAGE_MEDIA_REMOVAL
            IOCTL_STORAGE_EJECT_MEDIA
            IOCTL_STORAGE_LOAD_MEDIA
            IOCTL_STORAGE_RESERVE
            IOCTL_STORAGE_RELEASE
            IOCTL_STORAGE_GET_MEDIA_TYPES

    Является ли диск read/only

  Запросы специфичные для дисков

    Получение размера устройства

    Получение размера блока на устройстве

    Получение геометрии

Windows:
    IOCTL_DISK_GET_DRIVE_GEOMETRY
    IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
    IOCTL_DISK_VERIFY
    IOCTL_DISK_FORMAT_TRACKS
    IOCTL_DISK_REASSIGN_BLOCKS
    IOCTL_DISK_PERFORMANCE
    IOCTL_DISK_IS_WRITABLE
    IOCTL_DISK_GET_LENGTH_INFO
    IOCTL_DISK_UPDATE_DRIVE_SIZE

Linux:
    BLKROSET   _IO(0x12,93)	// set device read-only (0 = read-write)
    BLKROGET   _IO(0x12,94)	// get read-only status (0 = read_write)
    BLKRRPART  _IO(0x12,95)	// re-read partition table
    BLKGETSIZE _IO(0x12,96)	// return device size /512 (long *arg)
    BLKFLSBUF  _IO(0x12,97)	// flush buffer cache
    BLKRASET   _IO(0x12,98)	// set read ahead for block device
    BLKRAGET   _IO(0x12,99)	// get current read ahead setting
    BLKFRASET  _IO(0x12,100)// set filesystem read-ahead
    BLKFRAGET  _IO(0x12,101)// get filesystem read-ahead
    BLKSECTSET _IO(0x12,102)// set max sectors per request
    BLKSECTGET _IO(0x12,103)// get max sectors per request
    BLKSSZGET  _IO(0x12,104)// get block device sector size
    BLKELVGET  _IOR(0x12,106,size_t) // elevator get
    BLKELVSET  _IOW(0x12,107,size_t) // elevator set

  Поддержка партиционирования

    Поддержка партиционирования (только некоторые OS)
        смотри раздел 8.3.1.11
            IOCTL_DISK_GET_DRIVE_LAYOUT
            IOCTL_DISK_GET_DRIVE_LAYOUT_EX
            IOCTL_DISK_SET_DRIVE_LAYOUT
            IOCTL_DISK_SET_DRIVE_LAYOUT_EX

  Запросы специфичные для CD

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

    IOCTL_CDROM_READ_TOC
    IOCTL_CDROM_SEEK_AUDIO_MSF
    IOCTL_CDROM_STOP_AUDIO
    IOCTL_CDROM_PAUSE_AUDIO
    IOCTL_CDROM_RESUME_AUDIO
    IOCTL_CDROM_GET_VOLUME
    IOCTL_CDROM_PLAY_AUDIO_MSF
    IOCTL_CDROM_SET_VOLUME
    IOCTL_CDROM_READ_Q_CHANNEL

  Запросы специчные для DVD

Запросы специфичные для DVD запросы тоже практически напрямую
мэпяться в соответсвующие SCSI команды для оптических устройств.

    IOCTL_DVD_START_SESSION
    IOCTL_DVD_READ_KEY
    IOCTL_DVD_SEND_KEY
    IOCTL_DVD_END_SESSION
    IOCTL_DVD_GET_REGION
    IOCTL_DVD_SEND_KEY2
    IOCTL_DVD_READ_STRUCTURE

  Запросы к уровню диска

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

Linux:
    block_device_operation{}
        open
        release
        ioctl
        media_changed
        revalidate_disk
    def_blk_fops
        open
        release
        llseek
        read
        write
        aio_read
        aio_write
        mmap
        fsysnc
        ioctl
        compat_ioctl
        readv
        writev
        sendfile


81.3.1.10. ТИПОВЫЕ СЦЕНАРИИ ПРИ РАБОТЕ С ДИСКОВЫМИ УСТРОЙСТВАМИ

THIS SECTION IS UNDER CONSTRUCTION

TODO: Нужна большая детализация

Собственно уровень физического диска в совокупности с портами и SCSILizeroм
обеспечивает выполнение основных сценариев:

  IDE/SATA

Инициализация:
1) В начале делается аппаратный сброс шины через контролер ну и таймаут соответсвующий
2) Затем пытаются выбрать устройства на шине
3) На устройстве запускают команду
     IDENTIFY IDE DEVICE
   эта команда использует PIO (то есть трансфер идет не через DMA).
   в результате получают информацию об устройстве

   Эта информация содержит размер устройства, какие режимы работы оно поддерживает,
   его геометрию (в ATA смысле).
4) Затем настраивают режимы работы контроллера (например UltraDMA)
   (С этим могут быть проблемы - например старые OS - которые не знают UltraDMA,
   не пытаются настраивать контроллер - в результате если в BIOS UltraDMA режим
   стоит по умолчанию, то у OS получается выполнить только IDENTIFY IDE DEVICE,
   а с остальными командами проблемы - особенно если это на VMware).

Init
====
    Bus Reset
    IDENTIFY IDE DEVICE
    SET FEATURES  (устанавливают режим передачи)
    Configure controller

Выполняется IDENTIFY IDE DEVICE команда
Смотрится тип устройства ATA/ATAPI.
Если ATA то определяем размер:
    смотрим есть ли поддержка LBA
    если нет то
        устройство CHS
        берем CHS параметры из DWORD по смещению 72h
    если да то
        берем DWORD по смещению 78h
        если он == 0x0FFFFFFF
            то у нас LBA48
                берем LBA48 из QWORD по смещению С8h
                используем LBA48 команды для работы
        иначе
            берем DWORD по смещению 78h

Init SATA AHCI
==============
    Bus Reset
    IDENTIFY IDE DEVICE
    Set FPDMA mode

Read
=====
    READ SECTORS    		LBA28  PIO
     или
    READ SECTORS EXT		LBA48  PIO
     или
    READ DMA			LBA28  DMA/UDMA
     или
    READ DMA EXT			LBA48  DMA/UDMA
     или
    READ DMA QUEUED    		LBA28  DMA/UDMA  out-of-order
     или
    READ DMA QUEUED EXT		LBA48  DMA/UDMA  out-of-order
     или
    READ FPDMA QUEUED		LBF48  NCQ

Write
======
    WRITE SECTORS    		LBA28  PIO
     или
    WRITE SECTORS EXT		LBA48  PIO
     или
    WRITE DMA			LBA28  DMA/UDMA
     или
    WRITE DMA EXT			LBA48  DMA/UDMA
     или
    WRITE DMA QUEUED    		LBA28  DMA/UDMA  out-of-order
     или
    WRITE DMA QUEUED EXT		LBA48  DMA/UDMA  out-of-order
       или
    WRITE FPDMA QUEUED		LBF48  NCQ

  SCSI-like

Инициализация:
1) В начале делается апаратный сбор шины
2) Затем сканируется шины и каждому устройству выдается
3) INQUIRY - что бы узнать что это за устройство
4) READ CAPACITY - что бы узнать количество блоков на устройстве и размер блока

Все это обрамляется командами TEST UNIT READY - потому что если Unit not ready -
то нет смысла ему давать какую ниюудь команду.

Init
=====
    TEST UNIT READY		как правило

    INQUIRY

    TEST UNIT  READY
    REQUEST SENSE		что бы знать если ли media

    {
    READ CAPACITY(10)	LBA32
    или
    READ CAPACITY(16)	LBA64
    }
    START/STOP UNIT		тоже используют

INQUIRY возвращает структуру которая содержит тип устройства,
а так же является ли устройство removable.

Тип устройства:
    00	Disk
    05	CD/DVD

Пример ответа SCSI диска на команду INQUIRY:
IBM DSAS-3540 (SCSI-2 Harddisk):
------------------------------------------------------------------------------
00000000: 00 00 02 02 8f 00 00 1a 49 42 4d 20 20 20 20 20   [  ..Џ  .IBM     ]
00000010: 44 53 41 53 2d 33 35 34 30 20 20 20 20 20 20 20   [DSAS-3540       ]
00000020: 53 34 37 4b 51 33 30 32 39 35 31 38 20 20 20 20   [S47KQ3029518    ]
00000030: 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00   [                ]
00000040: 00 00 00 00 00 00 00 00                           [                ]
------------------------------------------------------------------------------
*************** INQUIRY data ***************
00000000 : byte        00 Perepherial device type/qualifier
            * Disk
00000001 : byte        00 Removable (high bit)
00000002 : byte        02 Version
00000003 : byte        02 Interface depended field
00000004 : byte        8F Additional data length
00000005 : dump  (0003)  Interface depended field
00000005 :  00 00 1A                                         [...-------------]
00000008 : dump  (0008)  Vendor ID
00000008 :  49 42 4D 20 20 20 20 20                          [IBM     --------]
00000010 : dump  (0010)  Produce ID
00000010 :  44 53 41 53 2D 33 35 34 30 20 20 20 20 20 20 20  [DSAS-3540       ]
00000020 : dump  (0004)  Produce revision level
00000020 :  53 34 37 4B                                      [S47K------------]

READ CAPACITY возвращает размер сектора и количество секторов.
Правильное определение работает так:
Вначале даем READ CAPACITY(10), она возвращает данные:

    struct
    {
        ULONG LogicalBlockAddress;
        ULONG BytesPerBlock;
    } READ_CAPACITY_DATA;

Если LBA != 0xffffffff то используем LBA как размер диска, в противном
случае вызываем READ CAPACITY(16):

    struct
    {
        QWORD  LogicalBlockAddress;
        ULONG  BytesPerBlock;
        BYTE   Flags;
        BYTE   Reserved[19];
    } READ_CAPACITY16_DATA;

и используем уже 64-битный LBA.

Пример ответа на команду READ CAPACITY для CD-ROM.
****************************************************************************
*     capacity data
****************************************************************************
* 0000: 00 01 97 BF 00 00 08 00                           ........
****************************************************************************

Пример ответа на команду  READ CAPACITY для 100MB ZIP drive.
****************************************************************************
*     capacity data
****************************************************************************
* 0000: 00 02 FF FF 00 00 02 00                           ........
****************************************************************************

Read
====
    TEST UNIT READY
    REQUEST SENSE		что бы знать есть ли media
    PREVENT/ALLOW MEDIA REMOVAL (prevent)
    {
    READ CAPACITY(10)	LBA32
    или
    READ CAPACITY(16)	LBA64
    }
    {
X	READ(8)		LBA21/LEN8
    или
X	READ(10)	LBA32/LEN16
    или
X	READ(16)	LBA64/LEN32
        }
    PREVENT/ALLOW MEDIA REMOVAL (allow)

Write
=====
    TEST UNIT READY
    REQUEST SENSE		что бы узнать есть ли media
    {
    READ CAPACITY(10)	LBA32
    или
    READ CAPACITY(16)	LBA64
    }
    PREVENT/ALLOW MEDIA REMOVAL (prevent)
    {
X	WRITE(8)	LBA21/LEN8
    или
X	WRITE(10)	LBA32/LEN16
    или
X	WRITE(16)	LBA64/LEN32
    }
    PREVENT/ALLOW MEDIA REMOVAL (allow)


81.3.1.11. УРОВЕНЬ ПАРТИЦИЙ

THIS SECTION IS UNDER CONSTRUCTION

  Типы Media

  Что такое партиция?

Типичные записи в таблицах партиций для простых разделов

    Стартовый сектор партиции
    Длинна партиции
    Тип партиции  (как правило тип файловой системы которая на ней
               развернута)
    Флаги
        как правило
            Read only
            Hidden

    Разная дополнительная информация зависющая от схемы партиций.

  Различные вырианты размещения партиций

    Покрывают весь носитель			       [APM, ZFS, MBR]

    Находятся в контейнере другой схемы разделов   [BSD slices]

    Находятся в контейнере но описывают еще и разделы
    внешние к контейнеру другой схемы партиций в рамках своей
    схемы партиций

    Защищаются от другой схемы разделов            [GPT, LDM]

  Проблемы схем разделов:

    Перекрывающиеся разделы в пределах одной схемы
    Перекрывающиеся разделы в разных схемах

    Зацикленные схемы разделов [MBR]

          Разделы
          /    \
    Простые    Сложные

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

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

Тем не менее есть и исключения, например Windows позволяет партиционировать MBR и GPT
разделы, для этого надо послать соответсвующий IOCTL блочному устройству физического
диска (то есть драйверу класса диска). Но тем не менее для LDM разделов интерфейсов
ядра нету.

  API для схем партиций

  Операции с схемами разделов

  Установить схему партиций на диске

  Снести схему партиций на диске

  Сконвертировать схему партиций в другую схему партиций

        возможно в контейнере

  Создать том

  Удалить том

  Операции связанные с файловой системой:

  Отформатировать том заданной файловой системой

  Проверить файловую систему на томе

  Увеличить том

  Уменьшить том

  Для сложных схем разделов

    Создать группу дисков
    Добавить диск в группу дисков
        возможно с ролью
    Удалить диск из группы дисков

  Для сложных томов

  Создать Mirror

  Добавить Mirror

  Удалить Mirror

  Break Mirror

    Добавить spare или просто unused диск в RAID
    Replace RAID-5 column
    Удалить диск из RAID-5

    Reactivate Fault Toulerant Disk

На примере Windows:
    внутренние (MBR,GPT):
        IOCTL_GET_DRIVE_LAYOUT
        IOCTL_GET_DRIVE_LAYOUT_EX
        IOCTL_SET_DRIVE_LAYOUT
        IOCTL_SET_DRIVE_LAYOUT_EX
    на уровне приложений
        COM интерфейсы VDS

  MBR

Вариант MBR цепочка:

Вариант MBR матрешка:

Формат входа в таблицу MBR:
+00	BYTE	Boot Indicator
+01	BYTE	Start Head
+02	BYTE	Start Sector/Start Cylinder High
+03	BYTE	Start Cylinder Low
+04	BYTE	Filesystem Type
+05	BYTE	End Head
+06	BYTE	End Sector/End Cylinder High
+07	BYTE	End Cylinder Low
+08	DWORD	Start LBA of partition
+0C	DWORD	Length of partition (in sectors)

  Выравнивание партиций

Характерно только для MBR схемы

Выравнивание по геометрии
    Старые устройства - CHS адрессация
    Старый BIOS - CHS адрессация
    Оптимизация Boot-code

Выравнивание по 80h секторов
    Из-за физических секторов которые больше 512 байт

Другие схемы живут себе спокойно без выравнивания

  GPT

Вход в таблицу партиций GPT имеет следущий формат:
+00	16BYTEs	  GUID типа партиции
+10	16BYTEs	  GUID партиции
+20	QWORD	  LBA первого сектора партиции
+28	QWORD	  LBA последнего сектора партиции
+30	QWORD	  Флаги партиции
+38	72BYTEs	  Описание партиции (UNICODE строка)


81.3.1.12. УРОВЕНЬ SOFTWARE RAIDs

THIS SECTION IS UNDER CONSTRUCTION

Непосредственно о RAID можно прочитать в секции 55.10.0.

Чем вообще занимается уровень RAID? Обеспечивает работу с RAID.

  Restricted Simple

Restricted Simple volume (один последовательный кусок дискового пространства):

  Simple

Simple volume (все части находяться на одном диске):

  Spanned

Spanned volume:

  Stripe (RAID-0)

Striped Volume (RAID-0):

  Mirror (RAID-1)

Mirrored volume (RAID-1):

  Операции RAID-1

Генерация. (происходит при создании RAID-1):

Регенерация:

  Политики чтения RAID-1

Для RAID-1 существуют различные политики чтения:

Round Robin:

Preffered Plex:

Geometric:

Full:

Когда читаются все диски и проверяются данные.

Политика записи одна единственная - пишем на все тома.
(возможно в определенной последовательности).

  RAID-4

  RAID-5

RAID-5 volume:

  Политики чтения RAID-4/RAID-5

Fast:

Full:

  Политики записи RAID-4/RAID-5

  Вращения RAID-5

  Операции RAID-5

Генерация

Регенерация

  Поддержка RAID в системе команд дисков

Современные SCSI диски имеют дополнительный набор команд, который
может быть использован для эффективного построения Software RAIDs:

    XDREAD
    XDWRITE
    XDWRITEREAD
    XPWRITE
    итд

Об этом можно прочитать в разделе
81.3.1.3. СПЕЦИАЛЬНЫЕ FEATURES НА КОТОРЫЕ НАДО ОБРАТИТЬ ОСОБОЕ ВНИМАНИЕ

  Схемы partitions поддерживающие RAID

Сложные схемы партиций поддерживающие RAIDs

    LDM
    LVM
    MD
    GEOM

Современные файловые системы типа ZFS или BtrFS знают о структуре нижележащей
storage и как результат позволяют добиться еще большей оптимизации.

  Дополнительные I/O операции поддерживаемые Software RAID:


81.3.1.13. УРОВЕНЬ ЛОГИЧЕСКОГО ДИСКА

THIS SECTION IS UNDER CONSTRUCTION

Логический диск - блочное устройство, на котором размещается файловая система.

Откуда беруться логические диски:

  Логические диски - партиции

    партиции

  Software RAID логические диски

    Software RAID устройства

  Синтетические логические диски

    синтетические устройсва типа
        файловая система в файле
        всевозможные encrypted контейнеры
        файлы образов и backup
            например DMG
        диски виртуальных машин
            VMDK, VHD

  Ramdisk

        виртуальные диски (ramdisk)

Файловая система работает с логическими дисками

Основная информация нужная для вышележащих уровней о логическом диске:

    - Размер блока

    - Размер диска в блоках

    - геометрия

    А также всевозможные параметры
    - Является ли диск read/only или writable
    - Online или Offline

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

    - так же как правило всевозможная идентификационная информация типа
        номера устойства
        уникального GUID

    - В некоторых OS доступна также информация о партиции
        IOCTL_DISK_GET_PARTITION_INFO	(Windows specific)
        IOCTL_DISK_GET_PARTITION_INFO_EX


81.3.1.14. ФИЛЬТРАЦИЯ БЛОЧНЫХ УСТРОЙСТВ

THIS SECTION IS UNDER CONSTRUCTION

Зачем это надо?

    Те же причины что и для фильтрации физических устройств
        Логирование (Sniffering)
        Запрет определенных операций

    +

    Snapshot
    Sandbox

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

  Sandbox

  Snapshot

  Hot processing

Облегченный вариант для backup.
В отличии от snapshot не дает слепок тома а дает делать backup,
при этом если в защищаемые сектора пишут, то перехватывает
вычитывает старые данные и отдает backup.
Требует меньше ресурсов чем snapshot.


81.3.1.15. DISK ARBITRATION

THIS SECTION IS UNDER CONSTRUCTION

Отслеживание и нотификация событий

Media appear

Media disapper

File system mounted

File system unmounted

Mac OS X (DiskArbitration.framework)

Управление монтированием

    DASessionCreate
    DADiskMount
    DADiskUnmount
    DADiskEject
    DADiskRename
    DADiskSetOptions
    DADiskGetOptions
    DADiskCopyDescription
    DADiskClaim
    DADiskUnclaim
    DADiskCreateFromBSDName

    DARegisterDiskAppearedCallback
    DARegisterDiskDisappearedCallback
    DARegisterDiskDescriptionChangedCallback
    DARegisterDiskMountApprovalCallback
    DARegisterDiskUnmountApprovalCallback
    DARegisterDiskEjectApprovalCallback

Windows

Собственно в ядре это осуществляется с помощью PnP сallbacks.

NTSTATUS
  IoRegisterPlugPlayNotification(
    IN IO_NOTIFICATION_EVENT_CATEGORY  EventCategory,	//EventCategoryDeviceInterfaceChange
    IN ULONG  EventCategoryFlags,
        // PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
    IN PVOID  EventCategoryData  OPTIONAL,		// pointer to GUID
    IN PDRIVER_OBJECT  DriverObject,
    IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE  CallbackRoutine,
    IN PVOID  Context,
    OUT PVOID  *NotificationEntry
    );

typedef NTSTATUS (*PDRIVER_NOTIFICATION_CALLBACK_ROUTINE) (
    IN PVOID NotificationStructure,
    IN PVOID Context
    );

typedef struct _DEVICE_INTERFACE_CHANGE_NOTIFICATION {
  USHORT  Version;
  USHORT  Size;
  GUID  Event;
  //
  // Event-specific data
  //
  GUID  InterfaceClassGuid;
  PUNICODE_STRING  SymbolicLinkName;
} DEVICE_INTERFACE_CHANGE_NOTIFICATION, *PDEVICE_INTERFACE_CHANGE_NOTIFICATION;

GUID_DEVICE_INTERFACE_ARRIVAL
GUID_DEVICE_INTERFACE_REMOVAL

GUID_DEVINTERFACE_VOLUME

Кроме этого FSD тоже нотифицирует о своих событиях PnP с помощью

NTSTATUS  FsRtlNotifyVolumeEvent(IN PFILE_OBJECT  FileObject,
                 IN ULONG  EventCode );

 --------------------------------------------------------------------------
Event		Event Code 		      PnP Event GUID
 --------------------------------------------------------------------------
Dismount	FSRTL_VOLUME_DISMOUNT 	      GUID_IO_VOLUME_DISMOUNT
Dismount failed	FSRTL_VOLUME_DISMOUNT_FAILED  GUID_IO_VOLUME_DISMOUNT_FAILED
Force read only FSRTL_VOLUME_FORCED_CLOSED    GUID_IO_VOLUME_FORCE_CLOSED
Media changed   FSRTL_VOLUME_INFO_MAKE_COMPAT GUID_IO_VOLUME_INFO_MAKE_COMPAT
Lock            FSRTL_VOLUME_LOCK 	      GUID_IO_VOLUME_LOCK
Lock failed     FSRTL_VOLUME_LOCK_FAILED      GUID_IO_VOLUME_LOCK_FAILED
Mount           FSRTL_VOLUME_MOUNT 	      GUID_IO_VOLUME_MOUNT
Need check fs   FSRTL_VOLUME_NEEDS_CHKDSK     GUID_IO_VOLUME_NEED_CHKDSK
Unlock          FSRTL_VOLUME_UNLOCK 	      GUID_IO_VOLUME_UNLOCK
Wearing out	FSRTL_VOLUME_WEARING_OUT      GUID_IO_VOLUME_WEARING_OUT
WORM near full  FSRTL_VOLUME_WORM_NEAR_FULL   GUID_IO_VOLUME_WORM_NEAR_FULL
 --------------------------------------------------------------------------


81.3.1.50. ОСОБЕННОСТИ РАБОТЫ С ОПТИЧЕСКИМИ НАКОПИТЕЛЯМИ

  Структура оптических носителей

THIS SECTION IS UNDER CONSTRUCTION

  Типовые сценарии

Read CD-ROM
============
    TEST UNIT READY
    PREVENT/ALLOW MEDIA REMOVAL
    READ CAPACITY
    READ TOP/PMA/ATIP		(read TOC)
X	READ (10)			(read actual data)
    PREVENT/ALLOW MEDIA REMOVAL

Play Audio CD
=============
    TEST UNIT READY
    PREVENT/ALLOW MEDIA REMOVAL
    READ DISK INFORMATION
    READ CAPACITY
    READ TOC/PMA/ATIP
    PLAY AUDIO MSF			(play audio)
|XX	READ SUB-CHANNEL		(current disk position)
    PAUSE/RESUME
    SEEK        			(seek to other position)
    PAUSE/RESUME
|XX	READ SUB-CHANNEL		(current disk position)
    PAUSE/RESUME
    PREVENT/ALLOW MEDIA REMOVAL
    START/STOP UNIT			(eject)

Write CD-R disk (data)
=======================
    TEST UNIT READY
    INQUIRY
    PREVENT/ALLOW MEDIA REMOVAL
    MODE SENSE 			(capabilites & mechanics)
    READ DISK IFFORMATION
    READ TRACK/RZONE INFORMATION
|X	SET CD SPEED
|X	MODE SENSE			(CD/DVD capabilities)
    READ BUFFER CAPACITY
|XX	WRITE(10)
|XX	READ BUFFER CAPACITY		(current buffer)
    SYNCHRONIZE CACHE
    again mode selection, polling disk params and so
    CLOSE TRACK/RZONE/SESSION/BORDER
    PREVENT/ALLOW MEDIA REMOVAL

Erase CD-RW
============
    TEST UNIT READY
    PREVENT/ALLOW MEDIA REMOVAL
    BLANK				(minimal blank disk)
X!!	TEST UNIT READY			(wait while unit ready)
    PREVENT/ALLOW MEDIA REMOVAL

Format CD-RW
=============
    TEST UNIT READY
    PREVENT/ALLOW MEDIA REMOVAL
    MODE SENSE			(CD/DVD capabilites & mech. status)
    READ DISK INFORMATION
    MODE SENSE			(write parameters)
    MODE SELECT			(write parameters)
    FORMAT UNIT
X!!	TEST UNIT READY
    READ DISK INFORMATION
    MODE SENSE			(write parameters)
    MODE SELECT			(write parameters)
    READ TRACK/RZONE INFORMATION
    READ DISK INFORMATION
    READ TOC/PMA/ATIP		(full TOC)
X	READ(10)			(verify entire disk)
    MODE SENSE			(write parameters)
    MODE SELECT			(write parameters)
|XX 	WRITE(10)			(write UDF filesystem)
| X	SYNCHRONIZE CACHE		(flush after sometimes)
|X      READ(10)			(verify, what we write)
    PREVENT/ALLOW MEDIA REMOVAL


81.3.1.50. ОСОБЕННОСТИ РАБОТЫ С MEDIA CHANGERS (JUKEBOX)

THIS SECTION IS UNDER CONSTRUCTION

Практически все IOCTLs которые предлагает система напрямую
отображаются в соответсвующие SCSI команды.

    IOCTL_CHANGER_GET_PARAMETERS
    IOCTL_CHANGER_GET_STATUS
    IOCTL_CHANGER_GET_ELEMENT_STATUS
    IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS
    IOCTL_CHANGER_SET_POSITION
    IOCTL_CHANGER_EXCHANGE_MEDIUM
    IOCTL_CHANGER_MOVE_MEDIUM


81.3.1.51. ОСОБЕННОСТИ РАБОТЫ С ЛЕНТОЧНЫМ STORAGE

THIS SECTION IS UNDER CONSTRUCTION

  Типовая структура ленты

BOM	Beginning of media
                    --+
BOP x	Beginning of partition	          | нумерация партиций
    .....                             | начинается с нуля
EW  x	Early warning for partition       |
    ....                              |
EOP x	End of partition                  |
                    --+
    ...
EW	Early warning for media
    ...
EOM	End of media

  Система команд для ленты

THIS SECTION IS UNDER CONSTRUCTION

    IOCTL_TAPE_ERASE
    IOCTL_TAPE_PREPARE
    IOCTL_TAPE_WRITE_MARKS
    IOCTL_TAPE_GET_POSITION
    IOCTL_TAPE_SET_POSTION
    IOCTL_TAPE_GET_DRIVE_PARAMS
    IOCTL_TAPE_SET_DRIVE_PARAMS
    IOCTL_TAPE_GET_MEDIA_PARAMS
    IOCTL_TAPE_SET_MEDIA_PARAMS
    IOCTL_TAPE_GET_STATUS

    IOCTL_TAPE_CREATE_PARTITION

    ну и к этому всему стандартный storage набор на removable media
    и reserve/release unit.


81.3.2.0. ОРГАНИЗАЦИЯ ФАЙЛОВЫХ СИСТЕМ

THIS SECTION IS UNDER CONSTRUCTION

Собственно организация файловой системы - это дерево:

  Кластеры

Распределение свободного места

file slack

  Superblock

Находится по фиксированным адрессам
По нему определяют файловую систему
Описывает параметры файловой системы

  Организация Inodes

вариант 1: Статический - Жесткое размещение на диске
(Количество inodes фиксированно и изменению не подлежит)

Вариант 2: Динамический - Хранение Inodes в метафайле
(При необходимости можем увеличивать размер метафайла)

  Что содержит inode?

THIS SECTION IS UNDER CONSTRUCTION

Метаданные:
    Размер файла
    Времена файла
    Количество жестких ссылок
    Аттрибуты файла
    Access Control (permissions или ACL, Owners)
    Структуры размещения данных файла
    Структуры размещения EA
    итд

Времена файла:

Mac OS X 10.6 Snow Leopard ввел новое время - время последнего backup
(им это удобно для Time Machine).

  Организация свободного места

  Фрагментация

  Организация размещения файлов

FAT (File Allocation Table):

UNIX:

Extents:

Размеры потоков файла для обычных файлов:

Размеры потоков файла для зашифрованных файлов:

  Организация директорий

Типичный вход в директорию

Минимально возможная информация, которая находится во входе директории
это имя файла, а также индекс его inode.
Остальные поля - это optional. (Файловая система может хранить всю остальную
метаинформацию в inode).

Собсвенно директория - это последовательность входов в директорию:

Или дерево входов в директорию отсортированное по соответсвующим ключам
(как правило имя файла (иногда hash имени))

Различные политики поведения при удалении входа в директорию
(дыра или сдвиг)

Различные политики на выравнивание входов в директорию
(может или не можен вход в директорию пересекать границу allocation
block для директории (как правило кластер):

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

  Типовые примеры


81.3.2.0.0. СТАНДАРТНЫЕ СВОЙСТВА ОБЪЕКТОВ ФАЙЛОВОЙ СИСТЕМЫ

THIS SECTION IS UNDER CONSTRUCTION

  Аттрибуты

  Windows

FILE_ATTRIBUTE_READONLY
    Предохраняет от записи. Даже если есть права на запись открыть такой
    файл на запись нельзя. Что бы это сделать надо сначала снять этот
    аттрибут с файла.

FILE_ATTRIBUTE_HIDDEN
    Не показывается при просмотре директории стандартной командой 'dir'.
    Обычно используется для того чтобы прятать системные файлы.

FILE_ATTRIBUTE_SYSTEM
    Указывает что это системный файл (соответсвенно его нельзя перемещать
    при дефрагментации).

FILE_ATTRIBUTE_ARCHIVE
    Устанавливается автоматически при создании файла или его модификации.
    Удобно для backup утилит, после того как забэкапят файл этот бит
    сбрасывается backup программой.

FILE_ATTRIBUTE_DIRECTORY
    Установлен у директорий

FILE_ATTRIBUTE_COMPRESSED
    Указывает что файл закомпрессирован

FILE_ATTRIBUTE_ENCRYPTED
    Указывает что файл зашифрован

FILE_ATTRIBUTE_NO_CONTEXT_INDEXED
    Говорит о том что файл не надо индексировать (Индексирование осуществляет
        Indexing Service).

FILE_ATTRIBUTE_OFFLINE
    Флаг говорит о том, что файл не находится непосредственно в файловой
    системы. И что для доступа к нему требуется его вытаскивание с внешнего
        хранилища (HSM)

FILE_ATTRIBUTE_REPARSE_POINT
    Типа символьной ссылки (как на директорию так и на другой том)

FILE_ATTRIBUTE_SPARSE_FILE
    Указывает что файл разряженный

    // FILE_ATTRIBUTE_NORMAL		// file or dir w/o other attributes set
    // FILE_ATTRIBUTE_TEMPORARY
    // FILE_ATTRIBUTE_VIRTUAL

  UNIX

Other Execute
Other Write
Other Read
Group Execute
Group Write
Group Read
Owner Execute
Owner Write
Owner Read
Sticky Bit
Set GID
Set UID
Type
    Regular file
    Directory
    Character device
    Block device
    Symbolic Link
    FIFO

Special attributes:

    EXT3_APPEND_FL
    EXT3_IMMUTABLE_FL
        считайте что это аналог READONLY для Windows
        пока не снимите, можно только читать файл, писать нельзя
    EXT3_NODUMP
    EXT3_SYNC_FL

  Novell Netware

Novell Netware file attributes (DOS Namespace):

READ_ONLY_BIT		 	00000001
HIDDEN_BIT		 	00000002
SYSTEM_BIT		 	00000004
EXECUTE_BIT		 	00000008
SUBDIRECTORY_BIT	 	00000010
ARCHIVE_BIT		 	00000020
SHARABLE_BIT		 	00000080
TRANSACTION_BIT		 	00001000
READ_AUDIT_BIT		 	00004000
WRITE_AUDIT_BIT		 	00008000
IMMEDIATE_PURGE_BIT	 	00010000
RENAME_INHIBIT_BIT	 	00020000
DELETE_INHIBIT_BIT	 	00040000
COPY_INHIBIT_BIT	 	00080000
FILE_AUDITING_BIT	 	00100000
REMOTE_DATE_ACCESS_BIT	 	00400000
REMOTE_DATE_INHIBIT_BIT	 	01000000
REMOTE_DATE_SAVE_KEY_BIT    	02000000
COMPRESS_FILE_IMMEDIATE_BIT     20000000
DO_NOT_COMPRESS_FILE_BIT	80000000

  Времена файлов

    Creation Time
    Modification Time
    Last Access Time
    Last Write time for metadata
    Last Backup Time


81.3.2.0.1. ОБЪЕКТЫ ФАЙЛОВЫХ СИСТЕМ

THIS SECTION IS UNDER CONSTRUCTION

  Обычный файл

  Директория

  Hardlink

  Multiple-streams file

  Sparse file

  Compressed file

  Compressed folder

  Compressed volumes

  Device File

  Encrypted file

  Encrypted Folder

  Symbolic Link

  Volume mount point

  Reparse point

  SIS Reparse Point

  HSM Reparse point

  Extended Attributes

  Object ID

  Volume Serial Number

  Volume Label


81.3.2.0.2. ДИСКОВЫЕ КВОТЫ

THIS SECTION IS UNDER CONSTRUCTION

  Что такое дисковая квота?

  Интерфейсы дисковых квот

    Получить информацию о квотах

    Установить информацию о квотах

Win32 COM интерфейсы:
    IDiskQuotaControl
    IDiskQuotaUser
    IDiskQuotaEvents

В конце концов доходит до Native API:

 Windows

NTSTATUS NTAPI NtQueryQuotaInformationFile(
        IN  HANDLE	FileHandle,	// volume
        OUT PIO_STATUS_BLOCK  IoStatusBlock,
        OUT PFILE_USER_QUOTA_INFORMATION Buffer,
        IN  ULONG  	BufferLength,
        IN  BOOLEAN	ReturnSingleEntry,
        IN  PFILE_QUOTA_LIST_INFORMATION QuotaList OPTIONAL,
        IN  ULONG	QuotaListLength,
        IN  PSID	ResumeSid  OPTIONAL,
        IN  BOOLEAN	RestartScan);

NTSTATUS NTAPI NtSetQuotaInformationFile(
        IN  HANDLE	FileHandle,	// volume
        OUT PIO_STATUS_BLOCK  IoStatusBlock,
        IN  PFILE_USER_QUOTA_INFORMATION Buffer,
        IN  ULONG	BufferLength);

typedef struct _FILE_USER_QUOTA_INFORMATION
{
    ULONG	NextEntryOffset;
    ULONG	SidLength;
    LARGE_INTEGER	ChangeTime;
    LARGE_INTEGER	QuotaUsed;
    LARGE_INTEGER	QuotaTreshold;
    LARGE_INTEGER	QuotaLimit
    SID		Sid[1];
} FILE_USER_QUOTA_INFORMATION, * PFILE_USER_QUOTA_INFORMATION;

typedef struct _FILE_QUOTA_LIST_INFORMATION
{
    ULONG	NextEntryOffset;
    ULONG	SidLength;
    SID	Sid[1];
} FILE_QUOTA_LIST_INFORMATION, * PFILE_QUOTA_LIST_INFORMATION;

  Дисковые квоты на директории

Наиболее характеристически это проявляется в Novell Netware
доходя до квот на директории.

int	AddSpaceRestrictionForDirectory(
        char* path,
        int   restriction,
        LONG  allowWildCardFlag);

int	AddUserSpaceRestriction(
        int   volume,
        LONG  trusteeID,
        LONG  restriction)

int	GetDiskSpaceUsedByObject(
        LONG  trusteeID,
        int   volume,
        LONG* usedSpace);


81.3.2.0.3. СПЕЦИАЛЬНЫЕ СВОЙСТВА ФАЙЛОВЫХ СИСТЕМ

THIS SECTION IS UNDER CONSTRUCTION

  Журналирование

Собственно два уровня задач:
    1) Обеспечение consistancy структур файловой системы
       как правило транзакции
    2) Журнал изменений
       удобно смотреть приложениям кто что делал над файловой системой

  Snapshoting

    ZFS

Идея крайне простая - все данные в файловой системы снабжаются timestamp,
если делается снапшот то изменения вносяться в паралельное дерево объектов,
в результате чего имеем снапшот.
Кроме того имеем read/write snapshot ability.

  Smart RAID

    Зная структуру нижележащего storage файловая система может быть весьма
эффективной с точки зрения быстродействия.

Например - RAID-Z (ZFS)
Если надо записать короткие данные пишем их как Mirror
Если же идет полная полоса - пишем ее как RAID-5.

  Deduplication

    Современный ZFS
Так как данных храняться на томе то это полный target deduplication.
В метафайле держим дерево hash и ссылок (поскольку на уровне блоков то hash
должен быть довольно большой - сейчас используют 256 бит).
Если блок который хотят писать совпал по hash с некоторым блоком - читаем некоторый
блок, проверяем данные (это наша 100% гарантия от data loss). И если все оk,
то заменяем блок на ссылку на hash.

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

  Кластерные файловые системы

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

Для кластерных ФС также необходим откат блокировок в случае долгой неактивности
node.


81.3.2.1. VFS LAYER

THIS SECTION IS UNDER CONSTRUCTION


81.3.2.1.1. БЛОКИРОВКА ФАЙЛОВ

THIS SECTION IS UNDER CONSTRUCTION

Opportunitic Locking (OPLOCKS)

Для удаленного кэширования

Level I		кэширование для чтения и для записи
Level II	кэширование только для чтения

принцип сообщения о снятии locks
    отзыв oplock
    деградация oplock

После того как OPLOCK сорвался его уже не ставят.


81.3.2.2. CACHE MANAGER

THIS SECTION IS UNDER CONSTRUCTION

Собственно есть 3 основных вида объектов для кэширования, которые
используются:

1) Блоки Memory Mapped Files
   они расположены по границам страниц

2) Блоки буферного Cache
   Соответсвуют одному или нескольким кластерам
   Как правило тоже расположены по границам страниц
   (но их не мапируют в пользовательское пространство)

3) Структуры не находящиеся в буферном cache которые кэшируют
   (Например метаданные)
   [Хотя практически всегда можно сделать metafile и его закэшировать]

4) Структуры которые держат в памяти но cache manager не должен самостоятельно
   сбрасывать их на диск.
   [Используются для хранения записей в лог файл - которые идут естественно
    паралельно к cache manager]

  Примитивы Cache manager

  Создание и удаление cache

 Windows

NTKERNELAPI
VOID
CcInitializeCacheMap (
    __in PFILE_OBJECT FileObject,
    __in PCC_FILE_SIZES FileSizes,
    __in BOOLEAN PinAccess,
    __in PCACHE_MANAGER_CALLBACKS Callbacks,
    __in PVOID LazyWriteContext
    );

NTKERNELAPI
BOOLEAN
CcUninitializeCacheMap (
    __in PFILE_OBJECT FileObject,
    __in_opt PLARGE_INTEGER TruncateSize,
    __in_opt PCACHE_UNINITIALIZE_EVENT UninitializeEvent
    );

  Копирование в кэш и обратно

 Windows

NTKERNELAPI
BOOLEAN
CcCopyRead (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in BOOLEAN Wait,
    __out_bcount(Length) PVOID Buffer,
    __out PIO_STATUS_BLOCK IoStatus
    );

NTKERNELAPI
VOID
CcFastCopyRead (
    __in PFILE_OBJECT FileObject,
    __in ULONG FileOffset,
    __in ULONG Length,
    __in ULONG PageCount,
    __out_bcount(Length) PVOID Buffer,
    __out PIO_STATUS_BLOCK IoStatus
    );

NTKERNELAPI
BOOLEAN
CcCopyWrite (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in BOOLEAN Wait,
    __in_bcount(Length) PVOID Buffer
    );

NTKERNELAPI
VOID
CcFastCopyWrite (
    __in PFILE_OBJECT FileObject,
    __in ULONG FileOffset,
    __in ULONG Length,
    __in_bcount(Length) PVOID Buffer
    );

  Работа с метаданными Метаданные

    CcMapData
    CcPinRead
    CcPreparePinWrite
    CcPinMappedData
    CcSetDirtyPinnedData
    CcUnpinData

 Windows

NTKERNELAPI
BOOLEAN
CcPinRead (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG Flags,
    __deref_out PVOID *Bcb,
    __deref_out_bcount(Length) PVOID *Buffer
    );

NTKERNELAPI
BOOLEAN
CcMapData (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG Flags,
    __deref_out PVOID *Bcb,
    __deref_out_bcount(Length) PVOID *Buffer
    );

NTKERNELAPI
BOOLEAN
CcPinMappedData (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG Flags,
    __deref_inout PVOID *Bcb
    );

NTKERNELAPI
BOOLEAN
CcPreparePinWrite (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in BOOLEAN Zero,
    __in ULONG Flags,
    __deref_out PVOID *Bcb,
    __deref_out_bcount(Length) PVOID *Buffer
    );

NTKERNELAPI
VOID
CcSetDirtyPinnedData (
    __in PVOID BcbVoid,
    __in_opt PLARGE_INTEGER Lsn
    );

NTKERNELAPI
VOID
CcUnpinData (
    __in PVOID Bcb
    );
NTKERNELAPI
VOID
CcUnpinDataForThread (
    __in PVOID Bcb,
    __in ERESOURCE_THREAD ResourceThreadId
    );

  Управление файлами

NTKERNELAPI
VOID
CcSetFileSizes (
    __in PFILE_OBJECT FileObject,
    __in PCC_FILE_SIZES FileSizes
    );

NTKERNELAPI
BOOLEAN
CcPurgeCacheSection (
    __in PSECTION_OBJECT_POINTERS SectionObjectPointer,
    __in_opt PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG Flags
    );

NTKERNELAPI
VOID
CcFlushCache (
    __in PSECTION_OBJECT_POINTERS SectionObjectPointer,
    __in_opt PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __out_opt PIO_STATUS_BLOCK IoStatus
    );

NTKERNELAPI
BOOLEAN
CcZeroData (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER StartOffset,
    __in PLARGE_INTEGER EndOffset,
    __in BOOLEAN Wait
    );

NTKERNELAPI
VOID
CcScheduleReadAhead (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length
    );

NTKERNELAPI
VOID
CcSetReadAheadGranularity (
    __in PFILE_OBJECT FileObject,
    __in ULONG Granularity
    );

NTKERNELAPI
NTSTATUS
CcWaitForCurrentLazyWriterActivity (
    VOID
    );

Работа С физическими страницами
    (надо для увеличения performance)
    CcMdlRead
    CcMdlReadComplete
    CcMdlWrite
    CcMdlWriteComplete

 Windows

NTKERNELAPI
VOID
CcMdlRead (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __out PMDL *MdlChain,
    __out PIO_STATUS_BLOCK IoStatus
    );

NTKERNELAPI
VOID
CcMdlReadComplete (
    __in PFILE_OBJECT FileObject,
    __in PMDL MdlChain
    );

NTKERNELAPI
VOID
CcPrepareMdlWrite (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __out PMDL *MdlChain,
    __out PIO_STATUS_BLOCK IoStatus
    );
NTKERNELAPI
VOID
CcMdlWriteComplete (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in PMDL MdlChain
    );

NTKERNELAPI		// WinXP
VOID
CcMdlWriteAbort (
    __in PFILE_OBJECT FileObject,
    __in PMDL MdlChain
    );

  Write throttling

    CcCanIWrite
    CcDeferWrite

 Windows

NTKERNELAPI
VOID
CcSetDirtyPageThreshold (
    __in PFILE_OBJECT FileObject,
    __in ULONG DirtyPageThreshold
    );

NTKERNELAPI
BOOLEAN
CcCanIWrite (
    __in PFILE_OBJECT FileObject,
    __in ULONG BytesToWrite,
    __in BOOLEAN Wait,
    __in UCHAR Retrying
    );

typedef
VOID (*PCC_POST_DEFERRED_WRITE) (
    __in PVOID Context1,
    __in PVOID Context2
    );

NTKERNELAPI
VOID
CcDeferWrite (
    __in PFILE_OBJECT FileObject,
    __in PCC_POST_DEFERRED_WRITE PostRoutine,
    __in PVOID Context1,
    __in PVOID Context2,
    __in ULONG BytesToWrite,
    __in BOOLEAN Retrying
    );

THIS SECTION IS UNDER CONSTRUCTION


81.3.2.3. ВИРТУАЛЬНОЕ КЭШИРОВАНИЕ

Организация виртуального кэширования требует тесного взаимодействия с операционной
системой.

Типовые проблемы и задачи возникающие при виртуальном кэшировании.

1) Нерезидентные файлы
   Некоторые файловые системы не выделяют для небольших файлов (данные которых могут
   поместиться в свободную часть inode) кластеров.
   В этом случае драйвер говорит что для файла виртуальное кэширование невозможно.

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

   Возможно и обратная ситуация - файл усеньшили и он может вместиться в резидентную часть.
   Для той части которая отбрасывается вызвается инвалидация (Virtual_Cache_Invalidate),
   для части которая попадает вызывается сброс в кластера и затем инвалидация
   (Virtual_cache_flush_then_Invalidate).

2) Перемещение данных файлов
   Примерно таже ситуайция возникает в системах типа BSD FFS, где если конец файла не
   укладывается в полный блок файловой системы, то его пишут в метафайлы каждый из которых
   хранит остатки в 1,2,3,... итд секторов.
   То есть такой перенос тоже вызывает инвалидацию.

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

4) Compressed files
   Прямой ввод-вывод тоже невозможен
   Как правило кроме виртуального кэширования система предоставляет API для простого
   кэширования - которые помогают держать в памяти метаданные.


81.3.2.4. FILESYSTEM FILTER DRIVERS

THIS SECTION IS UNDER CONSTRUCTION

    File system filters
        Antivirus
            Check  (+cure if possible)
            Block access (карантин)
        Reparse points
        Real time backup
        Undelete
        File filters
            directory quotas
            file masks for directory
                например нельзя записывать MP3 в директорию


81.3.2.5. FILE SYSTEM DRIVERS (FSD)

THIS SECTION IS UNDER CONSTRUCTION

  Концептуальный API для FSD

  Классический UNIX VFS вариант:

    UNIX вариант

    vfsops	для томы
        mount
        start
        unmount
        root
        quotactl
        getattr
        sync
        vfsop_get
        fhtovp
        vptofh
        init
        sysctl
        setattr
        ...

    vnops	для vnodes
        getattr получение аттрибутов
        setattr
        inactive - vnode становиться неактивной (например удалили) но еще живет
        revoke
        reclaim - полностью удаляется vnode
        pathconf - информация о поддержке возможностей
                максимальная длинна symbolic link
                максимальная длинна имени файла
                максимальная длинна пути
                case-sensitivity
                case-preserving
                extended attributes support
        lookup
        close
        open
        readdir
        fsync
        blockmap  - берет адресс кластера на диске
        blktooff
        offtoblk
        strategy
        read
        write
        create
        whiteout
        mknod
        symlink
        readlink
        readdirattr
        remove
        link
        rename
        mkdir
        rmdir
        allocate
        getxattr
        setxattr
        removexattr
        listxattr
        getattrlist
        mmap
        mnomap
        pagein
        pageout
        exchange
        kqfilt_add
        kqfilt_remove

  Linux дополнения

    Linux
        super_operations
            alloc_inode
            destroy_inode
            read_inode
            dirty_inode
            write_inode
            put_inode
            drop_inode
            delete_inode
            put_super
            write_super
            sync_fs
            write_super_lockfs
            unlockfs
            statfs
            remount_fs
            clear_inode
            umount_begin
            show_options

  Windows вариант

        IRP_MJ_CREATE
        IRP_MJ_CLOSE
        IRP_MJ_READ
        IRP_MJ_WRITE
        IRP_MJ_QUERY_INFORMATION
            FileBasicInformation
            FileStandardInformation
            FileInternalInformation
            FileEaInformation
            FileNameInformation
            FileCompressionInformation
            FilePositionInformation
            FileAllInformation
            FileStreamInformation
            (FileAccessInformation)
            (FileModeInformation)
            (FileAlignmentInformation)
        IRP_MJ_SET_INFORMATION
            FileDispositionInformation
            FileAllocationInformation
            FileEndOfFileInformation
            FileRenameInformation
        IRP_MJ_FLUSH_BUFFERS
        IRP_MJ_QUERY_VOLUME_INFORMATION
            FileFsVolumeInformation
            FileFsSizeInformation
            FileFsDeviceInformation
                FILE_REMOVABLE_MEDIA
                FILE_READ_ONLY_DEVICE
                FILE_FLOPPY_DISKETTE
                FILE_WRITE_ONCE_MEDIA
                FILE_REMOTE_DEVICE
                FILE_DEVICE_IS_MOUNTED
                FILE_VIRTUAL_VOLUME
            FileFsAttributeInformation
                FILE_CASE_SENSITIVE_SEARCH
                FILE_CASE_PRESERVED_NAMES
                FILE_UNICODE_ON_DISK
                FILE_PERSISTENT_ACKS
                FILE_FILE_COMPRESSION
                FILE_VOLUME_IS_COMPRESSED
        IRP_MJ_SET_VOLUME_INFORMATION
            FileFsLabelInformation
        IRP_MJ_DIRECTORY_CONTROL
            IRP_MN_QUERY_DIRECTORY
                FileDirectoryInformation
                FileFullDirectoryInformation
                FileBothDirectoryInformation
                FileNamesInformation
            IRP_MN_NOTIFY_CHANGE_DIRECTORY
        IRP_MJ_FILE_SYSTEM_CONTROL
            IRP_MN_USER_FS_REQUEST
                FSCTL_LOCK_VOLUME
                FSCTL_UNLOCK_VOLUME
                FSCTL_DISMOUNT_VOLUME
                FSCTL_MARK_VOLUME_DIRTY
                FSCTL_IS_VOLUME_MOUNTED
                FSCTL_IS_PATHNAME_VALID
                FSCTL_QUERY_RETRIEVAL_POINTERS
            IRP_MN_MOUNT_VOLUME
            IRP_MN_LOAD_FILE_SYSTEM
            IRP_MN_VERIFY_VOLUME
        IRP_MJ_DEVICE_CONTROL
        IRP_MJ_SHUTDOWN
        IRP_MJ_LOCK_CONTROL
            IRP_MN_LOCK
            IRP_MN_UNLOCK_SINGLE
            IRP_MN_UNLOCK_ALL
            IRP_MN_UNLOCK_ALL_BY_KEY
        IRP_MJ_CLEANUP
        IRP_MJ_QUERY_SECURITY
        IRP_MJ_SET_SECURITY
        IRP_MJ_QUERY_EA
        IRP_MJ_SET_EA
       FastIO
        FastIoCheckIfPossible
        FastIoRead
        FastIoWrite
        FastIoQueryBasicInfo
        FastIoQueryStandardInfo
        FastIoLock
        FastIoUnlockSingle
        FastIoUnlockAll
        FastIoUnlockAllByKey
        AcquireFileForNtCreateSection
        ReleaseFileForNtCreateSection
        FastIoQueryNetworkOpenInfo
        AcquireForModWrite
        ReleaseForModWrite
        AcquireForCcFlush
        ReleaseForCcFlush
        MdlRead
        MdlReadComplete
        PrepareMdlWrite
        MdlWriteComplete

TODO:
        FSCTLs

        FSCTL_IS_VOLUME_MOUNTED
        FSCTL_DISMOUNT_VOLUME

        FSCTL_LOCK_VOLUME
        FSCTL_UNLOCK_VOLUME

        FSCTL_MOVE_FILE

        FSCTL_EXTEND_VOLUME
        FSCTL_SHRINK_VOLUME

        FSCTL_QUERY_FILE_SYSTEM_RECOGNITION

        FSCTL_GET_RETRIEVAL_POINTERS
        FSCTL_GET_VOLUME_BITMAP

        FSCTL_CREATE_USN_JOURNAL
        FSCTL_DELETE_USN_JOURNAL
        FSCTL_ENUM_USN_DATA
        FSCTL_QUERY_USN_JOURNAL
        FSCTL_READ_FILE_USN_DATA

        FSCTL_CREATE_OR_GET_OBJECT_ID
        FSCTL_SET_OBJECT_ID
        FSCTL_GET_OBJECT_ID
        FSCTL_DELETE_OBJECT_ID

        FSCTL_SET_REPARSE_POINT
        FSCTL_GET_REPARSE_POINT

        FSCTL_GET_COMPRESSION
        FSCTL_SET_COMPRESSION

        итд

Тонкие моменты:

Обработка ошибок:  например возникли проблемы (например устройство исчезло)
          Надо провзаимодействовать с OS, чтобы выдать пользователю диалог типа
      Retry, Abort, Ignore и продолжить обработку после получения решения.

Мark volume dirty

Remount - устройство неожиданно вытащили и потом снова вставили
          соответвенно есть открытые объекты, несброшенные записи.
      (Volume Tracker для Floppy)

  Получение размещение файлов

Используется в первую очередь дефрагментаторамиъ
А так же всякими snapshot-like


81.3.2.5.1. FILESYSTEM ABILITIES

THIS SECTION IS UNDER CONSTRUCTION

Windows:
    FILE_CASE_SENSITIVE_SEARCH
    FILE_CASE_PRESERVED_NAMES
    FILE_UNICODE_ON_DISK
    FILE_PERSISTENT_ACLS
    FILE_FILE_COMPRESSION
    FILE_VOLUME_QUOTAS
    FILE_SUPPORT_SPARSE_FILES
    FILE_SUPPORT_REPARSE_FILES
    FILE_SUPPORT_REMOTE_STORAGE
    FILE_SUPPORT_OBJECT_IDS
    FILE_SUPPORT_ENCRYPTION
    FILE_NAMED_STREAMS

MacOSX  vfsops getattr capabilities:

    VOL_CAP_FMT_PERSISTENTOBJECTIDS
    VOL_CAP_FMT_CASE_PRESERVING
    VOL_CAP_FMT_FAST_STATFS
    VOL_CAP_FMT_HIDDEN_FILES
    VOL_CAP_FMT_PATH_FROM_ID
    VOL_CAP_FMT_SYMBOLICLINKS
    VOL_CAP_FMT_HARDLINKS
    VOL_CAP_FMT_JOURNAL
    VOL_CAP_FMT_SPARSE_FILES
    VOL_CAP_FMT_ZERO_RUNS
    VOL_CAP_FMT_JOURNAL_ACTIVE
    VOL_CAP_FMT_CASE_SENSITIVE
    VOL_CAP_FMT_CASE_PRESERVING
    VOL_CAP_FMT_2TB_FILESIZE
    VOL_CAP_FMT_DECMPFS_COMPRESSION
    VOL_CAP_FMT_NO_ROOT_TIMES
    VOL_CAP_FMT_OPENDENYMODES

   interfases:
    VOL_CAP_INT_SEARCHFS
    VOL_CAP_INT_ATTRLIST
    VOL_CAP_INT_NFSEXPORT
    VOL_CAP_INT_READDIRATTR
    VOL_CAP_INT_EXCHANGEDATA
    VOL_CAP_INT_ALLOCATE
    VOL_CAP_INT_VOL_RENAME
    VOL_CAP_INT_ADVLOCK
    VOL_CAP_INT_FLOCK
    VOL_CAP_INT_EXTENDED_ATTR
    VOL_CAP_INT_NAMEDSTREAMS;


81.3.2.6. АВТОМОНТИРОВАНИЕ - КАК ЭТО РАБОТАЕТ?

THIS SECTION IS UNDER CONSTRUCTION

В UNIX мы монтируем файловые системы явно - запуская утилиту mount, которая выполняет
системный вызов mount(), при этом явно указывается тип файловой системы.
И автомонтирование в UNIX - это чисто монтирование всех файловых систем которые описаны
в файле fstab.

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

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

Драйвера которые обслуживают partition shemes создают устройства томов.
Для каждого такого устройства MountManagerу драйвера Volume Manager посылают нотификацию
о том что появилось новое устройство тома.

MountManager начинает запрашивать у такого устройства метаинформацию - в первую очередь его
интересует имя устройства (как правило \Device\HarddiskN\PartitionM), а так же постоянный
GUID устройства, по которому Mount Manager индексирует свою базу данных дисков.
(GUID обычно стоиться из ID диска (которое храниться в MBR), а так же из стартового адресса
и длинны партиции). Для GPT дисков GUID тома может браться непосредсвенно с GPT.

Затем Mount Manager смотрит свою базу данных. Если для тома с таким GUID уже есть информация
о букве он пытается использовать ее, если нету то назначает ее сам. Так же он создает
символическую ссылку  \DosDevice\F:  на устройтво \Device\HarddiskN\PartitionM (могут быть
и другие имена, если устройство Floppy или CD/DVD.

Паралельно нотифицируется система, которая запускает драйверы специального типа
FSR (File System Recognizer). Эти драйверы распознают файловую систему путем чтения секторов
с тома, и если она совпадает с той которую они поддерживают, то они грузят специальным
образом FSD (File System Driver). FSD монтирует том.
Если никто из FSR не смог распознать файловую систему, или если FSD отказался ее монтировать
из-за ошибок, то монтируется файловая система RAW.


81.3.2.7. ДИНАМИЧЕСКОЕ ИЗМЕНЕНИЕ РАЗМЕРА ТОМА

THIS SECTION IS UNDER CONSTRUCTION

Драйвер файловой системы должен быть aware о таких операциях

    FSCTL_EXTEND_VOLUME
    FSCTL_SHRINK_VOLUME

если grow это операция которую можно сделать практически всегда, то shrink
зависит от заполнености файловой системы

    IOCTL_VOLUME_QUERY_MINIMUM_SHRINK_SIZE
    IOCTL_VOLUME_PREPARE_FOR_SHRINK


81.3.2.8. ПОДДЕРЖКА СОЗДАНИЯ СНАПШОТОВ СО СТОРОНЫ FSD

THIS SECTION IS UNDER CONSTRUCTION

Flush

Flush and Hold Writes

Unhold writes


81.3.2.9. ОБСЛУЖИВАНИЕ ФАЙЛОВОЙ СИСТЕМЫ

THIS SECTION IS UNDER CONSTRUCTION

Как правило делается внешними утилитами

  Блокировка тома

Надо для того чтобы никто другой не мог залезть на том пока мы
осуществляем критическую операцию (например форматируем файловую систему)
Блокировка осуществляется FSD по специальным запросам от клиентов

  Создание файловой системы (Формат)

  Проверка файловой системы

Типовые ситуации при проверке файловой системы

1) Crosslinked files

2) Часть файла аллокирована в свобрдном месте

3) Есть несвободная область которая не принадлежит никаким
   объектам файловой системы

4) Файлы которые не принадлежат не одной директории
   (сканирование по inodes, результат пишем в lost+found).
   [Часто чекалки не обрабатывают ситуацию если пропал сам lost+found
    или корневая директория]

5) Битые структуры файловой системы
   все что можно востанавливается, остальное убивается

5) Зацикленные структуры аллокации (FAT)

  Дефрагментация файловой системы

Как правило используются специальные API FSD (или системы) с помощью
которых можно узнать а так же установить размещение файла по кластерам.

  Тюнинг параметров файловой системы

Вообще как правило 3rd party

    Изменение размера кластера
    Изменение количества inodes
    итд

  Undelete

Тоже внешние утилиты.


81.3.3. API ОПЕРАЦИОННЫХ СИСТЕМ ДЛЯ РАБОТЫ С ФАЙЛАМИ И ФАЙЛОВЫМИ СИСТЕМАМИ

THIS SECTION IS UNDER CONSTRUCTION

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


81.3.3.1. КОРНЕВЫЕ И НЕКОРНЕВЫЕ ФАЙЛОВЫЕ ПОДСИСТЕМЫ

    Файловая подсистема
    /              \
     Корневая        Некорневая
      UNIX            Win,Mac

Корневая: Есть корень файловой системы к нему в поддиректории можно монтировать тома.

Некорневая: Единого корня файловой системы нет, на верхнем уровне находятся тома которые
            определяются идентификаторами.
        Как правило идентификатор является либо буквой либо строкой.

      DOS, Win:    C:
      Mac	       Machintosh HD:
      Netware      SYS:

Cоответсвенно для некорневых систем присутсвует большее количество API,
потому что надо еще управлять томами.

Смешанная: Единого корня нет, но можно монтировать другие тома в директории.

тома могут как иметь буквы, так и монтироваться в поддиректории
(причем одно не мешает другому).

Например Windows 2000 NTFS:

    C:   \XX --> Volume mount point -> \Device\Harddisk2\Partition7

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

  Установка корня файловой системы

 UNIX

int	chroot(const char* path)    // Non standard

  Монтирование/Дизмонтирование

 UNIX

int	mount(const char * sourcedevice,	// Non standard
          const char * targetdir,
          const char * fstype,
          unsigned long flags,
          const void * data);

int	umount(const char* target);		// Non standard

Кроме этого есть возможность просмотреть точки монтирования в /ect/fstab:

 UNIX

// mntent.h

FILE *setmntent(const char *filename, const char *type);
struct mntent *getmntent(FILE *filep);
int addmntent(FILE *filep, const struct mntent *mnt);
int endmntent(FILE *filep);
char *hasmntopt(const struct mntent *mnt, const char *opt);

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

  Энумерация томов по буквам

 Windows

DWORD GetLogicalDrives(void);
    bit 0 - means 'A:'
    bit 1 - means 'B:'
    etc
    if bit = 1 then volume is present

DWORD GetLogicalDriveStrings(DWORD nBufferLength,LPTSTR lpBuffer);

  Энумерация томов

 Windows

HANDLE FindFirstVolume(
  LPTSTR lpszVolumeName,
  DWORD cchBufferLength
);

BOOL FindNextVolume(
  HANDLE hFindVolume,
  LPTSTR lpszVolumeName,
  DWORD cchBufferLength
);

BOOL FindVolumeClose(
  HANDLE hFindVolume
);

  Энумерация Mount Points

 Windows

HANDLE FindFirstVolumeMountPoint(
  LPTSTR lpszRootPathName,
  LPTSTR lpszVolumeMountPoint,
  DWORD cchBufferLength
);

BOOL FindNextVolumeMountPoint(
  HANDLE hFindVolumeMountPoint,
  LPTSTR lpszVolumeMountPoint,
  DWORD cchBufferLength
);

BOOL FindVolumeMountPointClose(
  HANDLE hFindVolumeMountPoint
);

  Работа с Mount Points

 Windows

BOOL SetVolumeMountPoint(
  LPCTSTR lpszVolumeMountPoint,
  LPCTSTR lpszVolumeName
);

BOOL DeleteVolumeMountPoint(
  LPCTSTR lpszVolumeMountPoint
);

BOOL GetVolumeNameForVolumeMountPoint(
  LPCTSTR lpszVolumeMountPoint,
  LPTSTR lpszVolumeName,
  DWORD cchBufferLength
);

  Получение типа тома

 Windows

UINT GetDriveType(LPCTSTR lpRootPathName);
    DRIVE_UNKNOWN
    DRIVE_NO_ROOT_DIR
    DRIVE_REMOVABLE
    DRIVE_FIXED
    DRIVE_REMOTE
    DRIVE_CDROM
    DRIVE_RAMDISK

  Sync

  Mount/Unmount

Собственно в Windows реализовано прозрачное монтирование/дизмонтирование.
Если том появляется, Windows его монтирует сама (кроме специальных случаев).

Об автомонтирование под Windows можно прочитать в секции
81.3.2.6. АВТОМОНТИРОВАНИЕ - КАК ЭТО РАБОТАЕТ?

Дизмонтирование тоже делает Windows. Но это можно сделать и программным путем

    FSCTL_LOCK_VOLUME	экслюзивный захват тома
    FSCTL_DISMOUNT_VOLUME	дизмонтирование тома

Правильное поведение - сначала залочить том, а потом уже его дизмонтировать,
иначе это будет Force Dismount.

Том будет дизмонтирован до первого обращения к нему, после чего он будет
снова автомонтироваться.


81.3.3.2. ТОМА ФАЙЛОВОЙ СИСТЕМЫ

    Структуры размещения файлов		Логический том

    Аллокирование свободного места
    Учет плохих блоков

    Расположение контейнера на диске	Физический том

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

Case-sensitivity:

Case-preserved:

API для томов файловой системы

Операции с томами
    Получить информацию о томе
        Имя файловой системы
        Серийный номер тома
        Метка тома
        Свойства файловой системы
            case-sensitive
            support ACL
            support compressed files
            support encrypted files
            support named data streams
            support sparse files
            support quotas
            support reparse points
    Установить информацию о томе
    Установить метку тома
    Получить размер свободного места на томе
    Получить тип тома
        Removable
        Fixed
        Remote
        CD/DVD
        Ramdisk
Квоты
    на всех пользователей (кроме root)
    на конкретного пользователя
        мягкая квота
        жесткая квота

UNIX API:

 UNIX

int	statvfs(const char* path, struct statvfs* buf)
int	fstatvds(int fd, struct statvfs* buf)

struct	statvfs
{
    unsigned long	f_bsize;
    unsigned long	f_frsize;
    unsigned long	f_blocks;
    usnigned long	f_bfree;
    unsigned long	f_avail;
    unsigned long	f_files;
    unsigned long	f_ffree;
    unsigned long	f_favail;
    unsigned long	f_fsid;
    unsigned long	f_flag;
                ST_NOATIME
                ST_MANDLOCK
                ST_NODEV
                ST_NODIRATIME
                ST_NOEXEC
                ST_NOSUID
                ST_RDONLY
                ST_SYNCHRONOUS
    unsigned long	f_namemax;
}

Получение abilities файловой системы:

 UNIX

// unistd.h

long int pathconf(const char* pathname, int name)	// by path
long int fpathconf(int fd, int name)			// by handle

    _PC_LINK_MAX		max number of links
    _PC_NAME_MAX            max name len
    _PC_PATH_MAX		max path len
    _PC_SYMLINK_MAX
    _PC_FILESIZEBITS

    _PC_MAX_CANNON		это уже к FIFO объектам
    _PC_MAX_INPUT
    _PC_PIPE_BUF

 Windows

BOOL GetVolumeInformation(
  LPCTSTR lpRootPathName,
  LPTSTR lpVolumeNameBuffer,
  DWORD nVolumeNameSize,
  LPDWORD lpVolumeSerialNumber,
  LPDWORD lpMaximumComponentLength,
  LPDWORD lpFileSystemFlags,
  LPTSTR lpFileSystemNameBuffer,
  DWORD nFileSystemNameSize
);

    FILE_NAMED_STREAMS
    FILE_READ_ONLY_VOLUME
    FILE_SUPPORTS_OBJECT_IDS
    FILE_SUPPORTS_REPARSE_POINTS
    FILE_SUPPORTS_SPARSE_FILES
    FILE_VOLUME_QUOTAS
    FS_CASE_IS_PRESERVED
    FS_CASE_SENSITIVE
    FS_FILE_COMPRESSION
    FS_FILE_ENCRYPTION
    FS_PERSISTENT_ACLS
    FS_UNICODE_STORED_ON_DISK
    FS_VOL_IS_COMPRESSED

BOOL WINAPI GetDiskFreeSpace(
  __in          LPCTSTR lpRootPathName,
  __out         LPDWORD lpSectorsPerCluster,
  __out         LPDWORD lpBytesPerSector,
  __out         LPDWORD lpNumberOfFreeClusters,
  __out         LPDWORD lpTotalNumberOfClusters
);

BOOL WINAPI GetDiskFreeSpaceEx(
  __in          LPCTSTR lpDirectoryName,
  __out         PULARGE_INTEGER lpFreeBytesAvailable,
  __out         PULARGE_INTEGER lpTotalNumberOfBytes,
  __out         PULARGE_INTEGER lpTotalNumberOfFreeBytes
);

 Windows

BOOL WINAPI SetVolumeLabel(
  __in          LPCTSTR lpRootPathName,
  __in          LPCTSTR lpVolumeName
);


81.3.3.3. ФАЙЛЫ

Аттрибуты файла
    Тип файла
        Обычный файл
        Директория
        Файл устройства (блочного, символьного)
        Symbolic Link
        Специальный файл (FIFO)
    Имя файла
        Win32 name (case-insensitive)
        POSIX semantic (case-sensitive)
        может содержать CodePage.
        Ну сейчас если не UNICODE, то UTF-8

        Файлы в Windows не могут содержать символы < > : " / \ |

    Времена файла
        Время создания
        Время последней модификации содержимого
        Время последней модификации метаданных файловой системы
        Время последнего доступа
        Время последнего backup (Mac OS X 10.6 Snow Leopard)

    Общие аттрибуты
        Только для чтения
        Hidden  (не должен показываться при обычном поиске по директории)
        System  (нельзя перемещать)
        Archive (был изменен)
    Специальные аттрибуты
        Sparse
        Symbolic Link
            Directory Junction
            Volume Mount Point
            HSM
        Compressed
        Encrypted
        Audit аттрибуты
            Read/Write/Rename/Delete
        Inhibit аттрибуты
            Rename/Delete/Copy/Date
    Права доступа
        UNIX file permisssion
            UID, GID
            UNIX Access mask
        ACL
            (SID, Permissions)
    Метаданные
        Extended Attributes (EA)
            как правило хранят метаданные системы типа
                тип приложения которым открывать файл  (MacOS)
                иконка которую показывать в shell      (OS/2)
                итд
        Альтернативные data streams (именованые data streams, MacOS forks)
        Системные метаданные
            Object ID
            Encrypted files keys
            WinFS indexes
            TxF (Transaction filesystem) info
    Жесткие ссылки
        файл может иметь много разных имен в разных директориях

    Не файлы
        Объекты которые расположены в файловой системе но реально не
        являются файлами, содержащими данные
            UNIX device files
            FIFO


81.3.3.4. API РАБОТЫ С ФАЙЛАМИ

         File API
           /         \
        by handle    by name

                by handle	by name
 -----------------------------------------------------------
Открытие/Создание		n/a		yes
Чтение/Письмо                   yes		---
Установка/запрос позиции        yes             ---
Установка/запрос размера	yes             ---
Сброс данных на диск		yes		---
Установка/запрос аттрибутов	yes		yes
Установка/запрос времен		yes		yes
Установка/запрос владельцев	yes		yes
Удаление      			sometimes	yes
Переименование                  ---		yes
Создание ссылки			---		yes
 -----------------------------------------------------------

Способы работы с файлами:
    Canonical mode
    Synchronous mode
    Memory mapping mode
    Direct I/O mode		(bypass page cache)
    Asynchronous mode

Операции с файлами
    эти операции как правило по handle

  Open/Create

    открыть/создать
        режим открытия
            для чтения
            для записи
            для чтения/записи
            для добавления (Append)
        режим совместного доступа
            share read
            share write
            share all
            share delete
        поведение при открытии
        Hints для ускорения
            Sequental access
            Random access

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

Совершенно особенный режим открытия Append. Другая семантика поведения.
В этом случае позиция в файле игнорируется и запись всегда ведется в самый конец файла
(что удобно если есть несколько паралельных программ пишущих в него - например если
это файл системного log).

  Поведение при открытии

Ситуация		Действие
Файл не существует	Вернуть ошибку
            Создать новый файл (естественно нулевой длинны)
Файл существует		Вернуть ошибку
            Открыть файл
            Урезать файл до нулевой длинны

  Access hints

  Append mode

  API для открытия/создания файлов

 UNIX

int	open(const char* name, int flags)
int	open(const char* name, int flags, mode_t mode)
    O_APPEND
    O_ASYNC
    O_CREAT
    O_DIRECT
    O_DIRECTORY
    O_EXCL			return error if file exist
    O_LARGEFILE
    O_NOCTTY
    O_NONBLOCK
    O_SYNC		O_DSYNC		O_RSYNC
    O_TRUNC

    S_IRWXU
    S_IRUSR
    S_IWUSR
    S_IXUSR
    S_IRWXG
    S_IRGRP
    S_IWGRP
    S_IXGRP
    S_IRWXO
    S_IROTH
    S_IWOTH
    S_IXOTH

int	creat(const char* name, mode_t mode)

mode_t	umask(mode_t cmask)
    open(pathname, O_CREAT, mode) = open(pathname, O_CREAT, (~mask) & mode);

int	close(int fd);

 UNIX

// unistd.h

int access(const char* path, int amode);
    // amode is:
    //	R_OK	- check for read access
    //	W_OK	- check for write access
    //	X_OK	- check for execute access
    //	F_OK	- check for exist

// Linux

int euidaccess(const char* path, int amode);

Собственно каждый file stream открывается отдельным вызовом.

 Windows

HANDLE CreateFile(
  LPCTSTR lpFileName,
  DWORD dwDesiredAccess,
  DWORD dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD dwCreationDisposition,
  DWORD dwFlagsAndAttributes,
  HANDLE hTemplateFile
);

    // dwDesiredAccess is:
    //	FILE_ALL_ACCESS
    //	FILE_APPEND_DATA
    //	FILE_READ_ATTRIBUTES
    //	FILE_READ_DATA
    //	FILE_READ_EA
    //	FILE_WRITE_ATTRIBUTES
    //	FILE_WRITE_DATA
    //	FILE_WRITE_EA
    //	GENERIC_READ
    //	GENERIC_WRITE
    //	SYNCHRONIZED

    // dwShareMode is:
    //	FILE_SHARE_READ
    //	FILE_SHARE_WRITE
    //	FILE_SHARE_DELETE

    // dwCreationDisposition is:
    //	CREATE_ALWAYS
    //	CREATE_NEW
    //	OPEN_ALWAYS
    //	OPEN_EXISTING
    //	TRUNCATE_EXISTING

    // dwFlagsAndAttributes is:
    //	содержит атрибуты для создание файла + флаги:
    //		FILE_FLAG_BACKUP_SEMANTICS
    //		FILE_FLAG_DELETE_ON_CLOSE
    //		FILE_FLAG_NO_BUFFERING
    //		FILE_FLAG_OPEN_NO_RECALL
    //		FILE_FLAG_OPEN_REPARSE_POINT
    //		FILE_FLAG_OVERLAPPED
    //		FILE_FLAG_POSIX_SEMANTICS
    //		FILE_FLAG_RANDOM_ACCESS
    //		FILE_FLAG_SEQUENTIAL_SCAN
    //		FILE_FLAG_WRITE_THROUGH

BOOL WINAPI CloseHandle(
  __in          HANDLE hObject
);

HANDLE WINAPI ReOpenFile(
  __in          HANDLE hOriginalFile,
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwShareMode,
  __in          DWORD dwFlags
);

Флаги для открытия файла для Windows Native API:

 Windows

NTSTATUS NTAPI NtCreateFile(
    OUT	PHANDLE	FileHandle,
    IN	ACCESS_MASK	DesiredAccess,
    IN	POBJECT_ATTRIBUTES  ObjectAttributes,
    OUT	PIO_STATUS_BLOCK  IoStatusBlock,
    IN	PLARGE_INTEGER   AllocationSize OPTIONAL,
    IN	ULONG	FileAttributes,
    IN	ULONG	ShareAccess,
    IN	ULONG	CreateDisposition,
    IN	ULONG	CreateOptions,
    IN	PVOID	EaBuffer  OPTIONAL,
    IN	ULONG	EaLength);

NtCreateFile
    Desired access
        DELETE
        FILE_READ_DATA
        FILE_WRITE_DATA
        FILE_EXECUTE		mapping I/O
        FILE_READ_ATTRIBUTES
        FILE_WRITE_ATTRIBUTES
        FILE_APPEND_DATA
        READ_CONTROL
        WRITE_DAC
        WRITE_OWNER
        FILE_LIST_DIRECTORY
        FILE_TRAVERSE
        FILE_READ_EA
        FILE_WRITE_EA
        SYNCHRONIZE
    Disposition
        FILE_SUPERSEDE
        FILE_CREATE
        FILE_OPEN
        FILE_OPEN_IF
        FILE_OVERWRITE
        FILE_OVERWRITE_IF
    Create option
        FILE_DIRECTORY_FILE
        FILE_NON_DIRECTORY_FILE
        FILE_WRITE_THROUGH
        FILE_SEQUENTIAL_ONLY
        FILE_RANDOM_ACCESS
        FILE_NO_INTERMEDIATE_BUFFERING	// sector size
        FILE_SYNCHRONOUS_IO_ALERT
        FILE_SYNCHRONOUS_IO_NOALERT
        FILE_CREATE_TREE_CONNECTION
        FILE_COMPLETE_IF_OPLOCKED
        FILE_NO_EA_KNOWLEDGE
        FILE_DELETE_ON_CLOSE
        FILE_OPEN_BY_FILE_ID
        FILE_OPEN_FOR_BACKUP_INTENT
        FILE_NO_COMPRESSION
        FILE_OPEN_FOR_RECOVERY
        FILE_OPEN_REPARSE_POINT
        FILE_OPEN_NO_RECALL
        FILE_OPEN_FOR_FREE_SPACE_QUERY

Изменение режима файла

Под UNIX бесполезно - не получиться. Только открыть еще раз.
Но можно менять состояние флага O_APPEND

// UNIX

    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_APPEND);
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_APPEND);

  Charset в именах файлов

Linux не имеет проблем, потому что файловые API используют кодировку UTF-8.

Windows для работы с файлами везде где используются имена имеет парные функции,
одна из них работает с UNICODE, другая с однобайтовыми/мультибайтовыми символами.

    CreateFileA
    CreateFileW  - UNICODE версия

На самом деле A-версия функций конвертирует имя в UNICODE, а потом вызывает W-версию
функции.

Проблема в том что консоль использует OEM кодировки, а GUI приложение ANSI кодировку.

 Windows

void WINAPI SetFileApisToANSI(void);	// per process
void WINAPI SetFileApisToOEM(void);	// per process

BOOL WINAPI AreFileApisANSI(void);

  Input/Output

Ранние системы например CP/M не позволяли обращаться к файлу по номеру байта,
они позволяли обмениваться только записями фиксированной длинны (например 128 байт,
соответсвенно выровненными). И даже длинна файла в директории была выражена не в
байтах а в записях. Поэтому текстовые файлы кончались символом с кодом EOF (26h),
что бы можно было понять где он кончился в блоке.
Остатки этого были и в ранних версиях UNIX - системный вызов seek().

    читать/писать
        последовательно
            указатель тек позиции
            seek
            проверка на конец файла
        случайный доступ
            указатель позиции включается
    запрос длинны файла

  Синхронный и асинхронный ввод/вывод

  Буферизация

  Scatter/Gather

  Seek

Сценарии для seek:

1) Собственно seek (то есть перемещение в позицию)
2) Получение текущей позиции
    pos = seek(CURRENT, 0)
3) Получение длинны файла
    pos = seek(CURRENT, 0)
    len = seek(END, 0)
    seek(BEGIN, pos)
4) Используется для установки размера файла там
   где нет атомарной операции для установки размера
    pos = seek(CURRENT, 0)
    seek(BEGIN, new_eof_position)
    SetEndOfFile()
    seek(BEGIN, pos)

Для случаев (3) и (4) если есть возможность то лучше
пользоваться атомарными операциями.

  Неполный ввод/вывод

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

ssize_t  read_all(int fd, void* buf, size_t len)
{
    ssize_t  current;
    ssize_t  total = 0;

    while (len)
    {
        current = read(fd, buf, len);

        if (errno == EINTR) continue;	// UNIX only

        if (current == 0) break;	// ошибка или end-of-file
        // прочитали частично
        buf = (void *) (((char *) buf) + current);
        len   -= current;
        total += current;
    }
    return	total;
}

  API файлового ввода/вывода

 UNIX

ssize_t	read(int fd, void* buf, size_t len)
ssize_t write(int fd, void* buf, size_t len)

off_t	lseek(int fd, off_t pos, int origin)
        SEEK_SET
        SEEK_CUR
        SEEK_END

ssize_t	pread(int fd, void* buf, size_t count, off_t pos)
ssize_t pwrite(int fd, const void* buf, size_t count, off_t pos)

ssize_t readv(int fd, const struct iovec* iov, int count)
ssize_t	writev(int fd, const struct iovec* iov, int count)

 UNIX

struct	iovec
{
    void*	iov_base;
    size_t	iov_len;
}

int	aio_read(struct aiocb* aicocbp)
int	aio_write(struct aiocb* aiocbp)
int	aio_error(const struct aiocb* aiocbp)
ssize_t	aio_return(struct aiocb* aiocbp)
int	aio_cancel(int fd, struct aiocb* aiocbp)
int	aio_fsync(int op, struct aiocb* aiocbp)
int	aio_suspend(const struct aiocb* const list[], int cbcnt, const struct timespec* timeout)

struct	aiocb
{
    int	  aio_fildes;
    off_t	  aio_offset;
    void*	  aio_buf;
    size_t	  aio_nbytes;
    int	  aio_reqprio;
struct	sigevent  aio_sigevent;
    int	  aio_lio_code;
}

TODO:
    poll
    select
    epoll_create	// Linux
    epoll_ctl
    epoll_wait

 Windows

BOOL WINAPI ReadFile(
  __in          HANDLE hFile,
  __out         LPVOID lpBuffer,
  __in          DWORD nNumberOfBytesToRead,
  __out         LPDWORD lpNumberOfBytesRead,
  __in          LPOVERLAPPED lpOverlapped
);

BOOL WINAPI WriteFile(
  __in          HANDLE hFile,
  __in          LPCVOID lpBuffer,
  __in          DWORD nNumberOfBytesToWrite,
  __out         LPDWORD lpNumberOfBytesWritten,
  __in          LPOVERLAPPED lpOverlapped
);

typedef struct _OVERLAPPED
{
    ULONG_PTR Internal;
    ULONG_PTR InternalHigh;
    union
    {
        struct
        {
            DWORD Offset;
            DWORD OffsetHigh;
        };
        PVOID Pointer;
    };
    HANDLE hEvent;
} OVERLAPPED,  *LPOVERLAPPED;

BOOL WINAPI ReadFileScatter(
  __in          HANDLE hFile,
  __out         FILE_SEGMENT_ELEMENT aSegmentArray[],
  __in          DWORD nNumberOfBytesToRead,
  __in          LPDWORD lpReserved,
  __in          LPOVERLAPPED lpOverlapped
);

BOOL WINAPI WriteFileGather(
  __in          HANDLE hFile,
  __in          FILE_SEGMENT_ELEMENT aSegmentArray[],
  __in          DWORD nNumberOfBytesToWrite,
         LPDWORD lpReserved,
  __in          LPOVERLAPPED lpOverlapped
);

typedef union _FILE_SEGMENT_ELEMENT {
    PVOID64   Buffer;
    ULONGLONG Alignment;
}FILE_SEGMENT_ELEMENT, *PFILE_SEGMENT_ELEMENT;

DWORD WINAPI SetFilePointer(
  __in          HANDLE hFile,
  __in          LONG lDistanceToMove,
  __in_out_opt  PLONG lpDistanceToMoveHigh,
  __in          DWORD dwMoveMethod
);

    // dwMoveMethod is:
    //	FILE_BEGIN
    //	FILE_CURRENT
    //	FILE_END

BOOL WINAPI SetFilePointerEx(
  __in          HANDLE hFile,
  __in          LARGE_INTEGER liDistanceToMove,
  __out_opt     PLARGE_INTEGER lpNewFilePointer,
  __in          DWORD dwMoveMethod
);

// основные асинхронные варианты

BOOL WINAPI ReadFileEx(
  __in          HANDLE hFile,
  __out         LPVOID lpBuffer,
  __in          DWORD nNumberOfBytesToRead,
  __in          LPOVERLAPPED lpOverlapped,
  __in          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

BOOL WINAPI WriteFileEx(
  __in          HANDLE hFile,
  __in          LPCVOID lpBuffer,
  __in          DWORD nNumberOfBytesToWrite,
  __in          LPOVERLAPPED lpOverlapped,
  __in          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

BOOL WINAPI CancelIo(
  __in          HANDLE hFile
);

BOOL WINAPI CancelIoEx(
  __in          HANDLE hFile,
  __in          LPOVERLAPPED lpOverlapped
);

// Старые версии Windows не поддерживают SetFilePointerEx(),
// а только SetFilePointer(). Этот snippet показывает как реализовать
// SetFilePointerEx() имеея SetFilePointer()

BOOL LegacySetFilePointerEx(
        HANDLE hFile,
        LARGE_INTEGER liDistanceToMove,
        PLARGE_INTEGER lpNewFilePointer,
        DWORD dwMoveMethod)
{
    LONG	high;		// high part
    DWORD	low;		// low part

    high = liDistanceToMove.HighPart;
    low = SetFilePointer(hFile,
                 liDistanceToMove.LowPart,
                 &high,
                 dwMoveMethod);

    if ((low == 0xffffffff) && (GetLastError() != NO_ERROR))
    {
        //- Error to positioning
        if (lpNewFilePointer)
        {
            lpNewFilePointer->LowPart = 0xffffffff;
            lpNewFilePointer->HighPart = -1;
        }
        return  FALSE;
    }

    if (lpNewFilePointer)
    {
        lpNewFilePointer->LowPart = low;
        lpNewFilePointer->HighPart = high;
    }
    return	TRUE;
}
#define	SetFilePointerEx  LegacySetFilePointerEx

  Multiplexing I/O

 UNIX

// sys/select.h

int select(int numfds, fd_set* readfds, fd_set* writefds,
       fd_set* exceptfds, struct timeval* timeout);

    FD_ZERO(fd_set* fds)
    FD_SET(int fd, fd_set* fds)
    FD_CLR(int  fd, fd_set* fds)
    FD_ISSET(int fd, fd_set* fds)

 UNIX

int poll(struct pollfd* fds, int numfds, int timeout);

struct pollfd
{
    int	fd;
    short	events;
    short	revents;
};
    POLLIN
    POLLOUT
    POLLPRI

    POLLERR
    POLLHUP
    POLLNVAL

 UNIX

// sys/select.h POSIX

int   pselect(fd_set* readfds,
              fd_set* writefds,
              fd_set* exceptfds,
          const struct timespec* timeout,
          const sigset_t* sigmask);

 UNIX

// Linux
// sys/epoll.h

int  epoll_create(int numdesc);
int  epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
int  epoll_wait(int epfd, struct epoll_event* event, int maxevent, int timeout);

    EPOLLIN
    EPOLLOUT
    EPOLLPRI

    EPOLL_CTL_ADD
    EPOLL_CTL_DEL
    EPOLL_CTL_MOD

    EPOLLERR
    EPOLLHUP

  установка длинны файла

 UNIX

int	ftruncate(int fd, off_t len)
int	truncate(const char* name, off_t len)

 Windows

DWORD WINAPI GetFileSize(
  __in          HANDLE hFile,
  __out         LPDWORD lpFileSizeHigh
);

BOOL WINAPI GetFileSizeEx(
  __in          HANDLE hFile,
  __out         PLARGE_INTEGER lpFileSize
);

BOOL WINAPI SetEndOfFile(
  __in          HANDLE hFile
);

Под Windows через Win32 установка новой длинны файла это комбинация между
SetEndOfFile() и SetFilePointer().
Тем не менее есть возможность через Native API установить длинну файла
непосредственно не трогая указатель позиции в файле:

 Windows

NTSYSAPI NTSTATUS NTAPI NtSetInformationFile(
        HANDLE	FileHandle,
        OUT	PIO_STATUS_BLOCK	IoStatusBlock,
        IN	PVOID	FileInformation,
        IN 	ULONG	FileInformationLength,
        IN	FILE_INFORMATION_CLASS  FileInformationClass);  // FileEmdOfFileInformation

typedef struct _FILE_END_OF_FILE_IFNFORMATION
{
    LARGE_INTEGER	EndOfFile;
} FILE_END_OF_FILE_INFORMATION, * PFILE_END_OF_FILE_INFORMATION;

  Сброс буферов файла на диск

    сброс буфферов на диск (flush/commit)
        данные + метаданные
        только данные

 UNIX

int	fsync(int fd)
int	fdatasync(int fd)
void	sync(void)

 Windows

BOOL WINAPI FlushFileBuffers(
  __in          HANDLE hFile
);

  Оптимизационные hints

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

 UNIX

// fcntl.h

int posix_fadvice(int fd, off_t offset, off_t len, int advice);
    // advice is
    //	POSIX_FADV_NORMAL
    //	POSIX_FADV_RANDOM
    //	POSIX_FADV_SEQUENTIAL
    //	POSIX_FADV_WILLNEED
    //	POSIX_FADV_NOREUSE
    //	POSIX_FADV_DONTNEED

ssize_t  readahead(int fd, off64_t offset, size_t count);	// Linux нестандартная

  Атрибуты и времена

    запросить аттрибуты
    установить аттрибуты

    запросить времена
    установить времена

 UNIX

int	stat(const char* path, struct stat* buf)
int	fstat(int fd, stryct stat* buf)
int	lstat(const char* path, struct stat* buf)

struct	stat
{
    dev_t		st_dev;
    ino_t		st_ino;
    mode_t		st_mode;
                S_IFBLK
                S_IFCHR
                S_IFDIR
                S_IFIFO
                S_IFLNK
                S_IFREG
                S_IFSOCK

                S_ISUID
                S_ISGID
                S_ISVTX

    nlink_t		st_nlink;
    uid_t		st_uid;
    gud_t		st_gid;
    dev_t		st_rdev;
    off_t		st_size;
    blksize_t       st_blksize;
    blkcnt_t	st_blocks;
    time_t		st_atime;	last access
    time_t		st_mtime;	last modification
    time_t		st_ctime;	last metadata modification
            st_atime_nsec;	// Linux
            st_mtime_nsec;	// Linux
            st_ctime_nsec;	// Linux
}

int	chmod(const char* path, mode_t mode)
inf	fchmod(int fd, mode_t mode)

int	utime(const char* path, const struct utimbuf* timebuf)

struct	utimbuf
{
    time_t	actime;		// access time
    time_t	modtime;	// modification time
}

int	utimes(char* filename, struct timeval tvp[2]);		// microsecond precision

 Windows

DWORD WINAPI GetFileAttributes(
  __in          LPCTSTR lpFileName
);

BOOL WINAPI SetFileAttributes(
  __in          LPCTSTR lpFileName,
  __in          DWORD dwFileAttributes
);

BOOL WINAPI GetFileTime(
  __in          HANDLE hFile,
  __out         LPFILETIME lpCreationTime,
  __out         LPFILETIME lpLastAccessTime,
  __out         LPFILETIME lpLastWriteTime
);

BOOL WINAPI SetFileTime(
  __in          HANDLE hFile,
  __in          const FILETIME* lpCreationTime,
  __in          const FILETIME* lpLastAccessTime,
  __in          const FILETIME* lpLastWriteTime
);

typedef struct _FILETIME
{
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME,  *PFILETIME;

BOOL WINAPI GetFileInformationByHandle(
  __in          HANDLE hFile,
  __out         LPBY_HANDLE_FILE_INFORMATION lpFileInformation
);

typedef struct _BY_HANDLE_FILE_INFORMATION
{
    DWORD dwFileAttributes;
    FILETIME ftCreationTime;
    FILETIME ftLastAccessTime;
    FILETIME ftLastWriteTime;
    DWORD dwVolumeSerialNumber;
    DWORD nFileSizeHigh;
    DWORD nFileSizeLow;
    DWORD nNumberOfLinks;
    DWORD nFileIndexHigh;
    DWORD nFileIndexLow;
} BY_HANDLE_FILE_INFORMATION,  *PBY_HANDLE_FILE_INFORMATION;

BOOL WINAPI SetFileInformationByHandle(
  __in          HANDLE hFile,
  __in          FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
            // FileBasicInfo
  __in          LPVOID lpFileInformation,
  __in          DWORD dwBufferSize
);

typedef struct _FILE_BASIC_INFO
{
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    DWORD FileAttributes;
} FILE_BASIC_INFO, *PFILE_BASIC_INFO;

Смена владельца файла гораздо более тяжелая операция чем в UNIX,
приходиться работать с SECURITY_DESCRIPTORs.

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

 UNIX

// Linux

int  ioctl(int fd, int request, void * arg);
    // request is
    //	EXT3_IOC_GETFLAGS
    //	EXT3_IOC_SETFLAGS

    // ars is:  pointer to int
    //	EXT3_APPEND_FL
    //	EXT3_IMMUTABLE_FL
    //	EXT3_NODUMP
    //	EXT3_SYNC_FL

  ACL (Access Control Lists)

    запрос ACL/UNIX     permissions
    установка ACL/UNIX  permissions

 Windows

DWORD WINAPI GetSecurityInfo(
      __in          HANDLE handle,
      __in          SE_OBJECT_TYPE ObjectType,
      __in          SECURITY_INFORMATION SecurityInfo,
      __out_opt     PSID* ppsidOwner,
      __out_opt     PSID* ppsidGroup,
      __out_opt     PACL* ppDacl,
      __out_opt     PACL* ppSacl,
      __out_opt     PSECURITY_DESCRIPTOR* ppSecurityDescriptor);

DWORD WINAPI SetSecurityInfo(
      __in          HANDLE handle,
      __in          SE_OBJECT_TYPE ObjectType,
      __in          SECURITY_INFORMATION SecurityInfo,
      __in_opt      PSID psidOwner,
      __in_opt      PSID psidGroup,
      __in_opt      PACL pDacl,
      __in_opt      PACL pSacl);

DWORD WINAPI GetNamedSecurityInfo(
      __in          LPTSTR pObjectName,
      __in          SE_OBJECT_TYPE ObjectType,
      __in          SECURITY_INFORMATION SecurityInfo,
      __out_opt     PSID* ppsidOwner,
      __out_opt     PSID* ppsidGroup,
      __out_opt     PACL* ppDacl,
      __out_opt     PACL* ppSacl,
      __out_opt     PSECURITY_DESCRIPTOR* ppSecurityDescriptor);

DWORD WINAPI SetNamedSecurityInfo(
      __in          LPTSTR pObjectName,
      __in          SE_OBJECT_TYPE ObjectType,
      __in          SECURITY_INFORMATION SecurityInfo,
      __in_opt      PSID psidOwner,
      __in_opt      PSID psidGroup,
      __in_opt      PACL pDacl,
      __in_opt      PACL pSacl);

 UNIX

int	chown(const char * path, uid_t owner, gid_t group)
int	lchown(const char* path, uid_t owner, gid_t group)
int	fchown(int fd, uid_t owner, gid_t group)

    // + пресловутый chmod

Дальше начинаются чудеса, потому что POSIX стандарт для ACL не был принят
поэтому у разных систем ACL имеют разные API

 UNIX

// FreeBSD/MacOSX
//	sys/acl.h

acl_t	acl_get_fd(int fd);					// Linux
acl_t   acl_get_fd_np(int fd, acl_type_t type);
acl_t   acl_get_file(const char *path_p, acl_type_t type);	// Linux
acl_t   acl_get_link_np(const char *path_p, acl_type_t type);

int     acl_set_fd(int fd, acl_t acl);				// Linux
int     acl_set_fd_np(int fd, acl_t acl, acl_type_t type);
int     acl_set_file(const char *path_p, acl_type_t type, acl_t acl);  // Linux
int     acl_set_link_np(const char *path_p, acl_type_t type, acl_t acl);

 UNIX

// Solaris
//	sys/acl.h

int 	acl(char *pathp, int cmd, int nentries, void *aclbufp);
int 	facl(int fildes, int cmd, int nentries, void *aclbufp);
    // cmd is:
    //	SETACL
    //	GETACL
    // 	GETACLCNT
    //	ACE_SETACL
    //	ACE_GETACL
    //	ACE_GETACLCNT

 UNIX

//  IRIX
//	sys/acl.h

struct acl* acl_get_file(const char *path, acl_type_t type);
struct acl* acl_get_fd(int fd);

int 	    acl_set_file(const char *path, acl_type_t type, struct acl *aclp);
int 	    acl_set_fd(int fd, struct acl *aclp);

 UNIX

// HPUX
//	aclv.h

int acl(char *pathp, int cmd, int nentries, struct acl *aclbufp);
    // cmd is:
    //	ACL_GET
    //	ACL_SET
    //	ACL_CNT

  Rename/Delete

   эти операции как правило по имени

    удаление файла
        если есть hardlinks то просто удаляется hardlink

    переименование файла

Собственно с переименованием (Rename/Move у нас возникает куча семантик):

 UNIX

int	unlink(const char* pathname)
int	rename(const char* oldpath, const char* newpath)
int	remove(const char* path)				// file or dir

собственно для UNIX системы:

    rename - это link на новое место, а потом unlink на старое.

 Windows

BOOL WINAPI MoveFile(
  __in          LPCTSTR lpExistingFileName,
  __in          LPCTSTR lpNewFileName
);

BOOL WINAPI MoveFileEx(
  __in          LPCTSTR lpExistingFileName,
  __in          LPCTSTR lpNewFileName,
  __in          DWORD dwFlags
);
    // dwFlags is:
    //	MOVEFILE_COPY_ALLOWED
    //	MOVEFILE_CREATE_HARDLINK	// reserved
    //	MOVEFILE_DELAY_UNTIL_REBOOT
    //	MOVEFILE_FAIL_IF_NOT_TRACKABLE
    //	MOVEFILE_REPLACE_EXISTING
    //	MOVEFILE_WRITE_THROUGH

BOOL WINAPI DeleteFile(
  __in          LPCTSTR lpFileName
);

Удаление файла в cовременных OS - это всегда установка флага DELETE_ON_CLOSE.

  Hard links

Жесткие ссылки
    Создать жесткую ссылку
    Удалить жесткую ссылку

 UNIX

int	link(const char* oldpath, const char* newpath)

 Windows

// Win2000+
BOOL WINAPI CreateHardLink(LPCTSTR lpFileName,
                 LPCTSTR lpExistingFileName,
                 LPSECURITY_ATTRIBUTES lpSecurityAttributes);

удаляются hardlinks обычными методами как и файлы:
    UNIX 	- unlink
    Windows - DeleteFile

Собственно говоря в ранних UNIX переименования файла делали через пару link/unlink.

Основная проблема связанная с hard links - это то что как правило нельзя проенумерировать
имена hard links. Это связано с структурой файловой системы.

NTFS такое позволяет (так как по записи в MFT можно найти все имена), и даже появились API:

 Windows

// Vista+
HANDLE WINAPI FindFirstFileNameW(LPCWSTR lpFileName,
                 DWORD dwFlags,			// 0
                 LPDWORD StringLength,
                 PWCHAR LinkName);

BOOL   WINAPI FindNextFileNameW(HANDLE hFindStream,
                    LPDWORD StringLength,
                PWCHAR LinkName);

BOOL WINAPI FindClose(HANDLE hFindFile);

  Symbolic Links

Символьные ссылки

    Создать символьную ссылку

    Прочитать символьную ссылку

 UNIX

int	symlink(const char* oldpath, const char* newpath)
ssize_t	readlink(const char* path, char* buf, size_t bufsize)

 Windows

// Windows Vista и позже. NTFS only.

BOOL WINAPI CreateSymbolicLink(LPCWSTR lpSymlinkFileName,
                     LPCWSTR lpTargetFileName,
                     DWORD dwFlags);
    //	dwFlags are:
    //				    0 - target is file
    //	SYMBOLIC_LINK_FLAG_DIRECTORY - target is directory

Что бы под Windows прочитать символическую ссылку надо открыть объект
с флагом FILE_FLAG_OPEN_REPARSE_POINT а затем использовать
FSCTL_GET_REPARSE_POINT.
Прочтите раздел "Специальные файлы" в этой секции ниже.

  File control

Специальное управление файлом
    ioctl
    sysctl
    fsctl

 UNIX

int	ioctl(int fd, int request, ...)
int	fcntl(int fd, int request, ...)
        F_DUPFD
        F_GETFD
        F_SETFD
        F_GETFL
        F_SETFL

        F_GETLK
        F_SETLK			non-blocked
        F_SETLKW		blocked

        F_SETLEASE		Linux oplock
        F_GETLEASE		Linux oplock

    fcntl(fd, F_SETFD, 1);		// set close-on-exec flag

  Handle management

    dup
    dup2

 UNIX

int	dup(int fd);			// dup(fd) = fcntl(fd, F_DUPFD, 0)
int	dup2(int fd, int fd2);		// dup2(fd, fd2) = close(fd2), fcntl(fd, F_DUPFD, fd2)

int	dup2(int oldfd, int newfd)
{
    close(newfd);	// to be sure that newfd will available
    return fcntl(oldfd, F_DUPFD, newfd);

 Windows

BOOL WINAPI DuplicateHandle(
  __in          HANDLE hSourceProcessHandle,
  __in          HANDLE hSourceHandle,
  __in          HANDLE hTargetProcessHandle,
  __out         LPHANDLE lpTargetHandle,
  __in          DWORD dwDesiredAccess,
  __in          BOOL bInheritHandle,
  __in          DWORD dwOptions
);

    // dwOptions is:
    //	DUPLICATE_CLOSE_SOURCE
    //	DUPLICATE_SAME_ACCESS

  Sharing

Совместный доступ

    Блокирование
        файла
        региона в файле

    разблокирование
        файла
        региона в файле

 UNIX

    fcntl
    F_XXXLK

struct	flock
{
    short	l_type;
            F_RDLCK
            F_WRLCK
            F_UNLCK	- remove locking
    short	l_whence;
    off_t	l_start;
    off_t	l_len;
    pid_t	l_pid;
}

int	lockf(int fd, int op, off_t len);

 Windows

BOOL WINAPI LockFile(
  __in          HANDLE hFile,
  __in          DWORD dwFileOffsetLow,
  __in          DWORD dwFileOffsetHigh,
  __in          DWORD nNumberOfBytesToLockLow,
  __in          DWORD nNumberOfBytesToLockHigh
);

BOOL WINAPI LockFileEx(
  __in          HANDLE hFile,
  __in          DWORD dwFlags,
            DWORD dwReserved,
  __in          DWORD nNumberOfBytesToLockLow,
  __in          DWORD nNumberOfBytesToLockHigh,
  __in          LPOVERLAPPED lpOverlapped
);

    // dwFlags
    //	LOCKFILE_EXCLUSIVE_LOCK		// иначе shared lock
    //	LOCKFILE_FAIL_IMMEDIATELY

BOOL WINAPI UnlockFile(
  __in          HANDLE hFile,
  __in          DWORD dwFileOffsetLow,
  __in          DWORD dwFileOffsetHigh,
  __in          DWORD nNumberOfBytesToUnlockLow,
  __in          DWORD nNumberOfBytesToUnlockHigh
);

BOOL WINAPI UnlockFileEx(
  __in          HANDLE hFile,
          DWORD dwReserved,
  __in          DWORD nNumberOfBytesToUnlockLow,
  __in          DWORD nNumberOfBytesToUnlockHigh,
  __in          LPOVERLAPPED lpOverlapped
);

  Специальные файлы

 UNIX

int	mknod(const char* path, mode_t perm, dev_t dev)
int 	mkfifo(const char *pathname, mode_t mode);
int 	mkfifoat(int dirfd, const char *pathname, mode_t mode); // relative to dir fd

    // perm is:
    //	кроме стандартных acesss rights
    //		S_IFCHR
    //		S_IFBLK
    //		S_IFIFO

Собственно в Windows специальных файлов нет, но есть Reparse Points
Они используются для создания:
    Symbolic Links (есть более простой interface)
    Volume Mount Points
    HSM reparse points
    SiS reparse points
    DFS reparse points
    итд

Работа с такими файлами происходит через DeviceIoControl()
    FSCTL_SET_REPARSE_POINT
    FSCTL_GET_REPARSE_POINT
    FSCTL_DELETE_REPARSE_POINT

    -------------------------------------------------
    FSCTL_SET_REPARSE_POINT		(Win2000+)

        lpInBuffer:
            REPARSE_GUID_DATA_BUFFER
        lpOutBuffer: NULL
    typedef struct _REPARSE_GUID_DATA_BUFFER
    {
            DWORD  ReparseTag;
            WORD   ReparseDataLength;
            WORD   Reserved;
            GUID   ReparseGuid;
            struct
        {
                   BYTE   DataBuffer[1];
            } GenericReparseBuffer;
    } REPARSE_GUID_DATA_BUFFER,
     *PREPARSE_GUID_DATA_BUFFER;
    --------------------------------------------------
    FSCTL_GET_REPARSE_POINT		(Win2000+)

        lpInBuffer: NULL
        lpOutBuffer:
            REPARSE_GUID_DATA_BUFFER
    -------------------------------------------------
    FSCTL_DELETE_REPARSE_POINT	(Win2000+)

        lpInBuffer:
            REPARSE_GUID_DATA_BUFFER
        lpOutBuffer:
            NULL
    -------------------------------------------------

  Extended Attributes

    Чтение EA

    Запись EA

    Удаление EA

 UNIX

// Linux
ssize_t	getxattr(const char* path, const char* key, void* value, size_t size)
ssize_t lgetxattr(const char* path, const char* key, void* value, size_t size)
ssize_t	fgetxattr(int fd, const char * key, void* value, size_t size)

int	setxattr(const char* path, const char* key, const void* value, size_t size, int flags)
int	lsetxattr(const char* path, const char* key, const void* value, size_t size, int flags)
int	fsetxattr(int fd, const char* key, const void* value, size_t size, int flags)

ssize_t	listxattr(const char* path, char* list, size_t size)
ssize_t llistxattr(const char* path, char* list, size_t size)
ssize_t flistxattr(int fd, char* list, size_t size)

int	removexattr(const char* path, const char* key)
int	lremovexattr(const char* path, const char* key)
int	fremovexattr(int fd, const char* key)

В Win32 нет непосредственно API для работы с Extended attributes, но зато есть Native API

 Windows

NTSYSAPI NTSTATUS NTAPI NtQueryEaFile(
    IN HANDLE	FileHandle,
    OUT PIO_STATUS_BLOCK	IoStatusBlock,
    OUT PFILE_FULL_EA_INFORMATION Buffer,
    IN ULONG	BufferLength,
    IN BOOLEAN	ReturnSingleEntry,
    IN PFILE_GET_EA_INFORMATION EaList OPTIONAL,
    IN ULONG	EaListLength,
    IN PULONG	EaIndex OPTIONAL,
    IN BOOLEAN	RestartScan);

NTSYSAPI NTSTATUS NTAPI NtSetEaFile(
    IN HANDLE	FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PFILE_FULL_EA_INFORMATION Buffer,
    IN ULONG  	BufferLength);

typedef struct _FILE_FULL_EA_INFORMATION
{
    ULONG	NextEntryOffset;
    UCHAR	Flags;
    UCHAR	EaNameLength;
    USHORT	EaValueLength;
    CHAR	EaName[1];
      //UCHAR   EaData[];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;

typedef struct _FILE_GET_EA_INFORMATION
{
    ULONG	NextEntryOffset;
    UCHAR	EaNameLength;
    CHAR	EaName[1];
} FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION;

  Compressed files

    Компресирование файла

    Декомпрессирование файла

 Windows

DWORD WINAPI GetCompressedFileSize(
  __in          LPCTSTR lpFileName,
  __out         LPDWORD lpFileSizeHigh
);

Для того чтобы сделать файл compressed  (реально компресируется не файл, а data stream)
под Windows нужно открыть этот файл и выполнить на нам FSCTL_SET_COMPRESSION:

HANDLE hcmp = CreateFile("SomeFile:SomeStream",
                 GENERIC_READ | GENERIC_WRITE,
                 0,
                 NULL,
                 OPEN_EXISTING,
                 0,
                 NULL);
    USHORT uscs = COMPRESSION_FORMAT_DEFAULT;
    DWORD  cb;

    DeviceIoControl(hcmp,FSCTL_SET_COMPRESSION,
                 &uscs,
                 sizeof(uscs),
                 NULL,
                 0,
                 &cb,
                 NULL);
    CloseHandle(hcmp);

  Sparse files

Типовые UNIX системы пологают что файл автоматически является sparse.
Windows так не пологает
В Windows для поддержки sparse files имеются следущие возможности

    FSCTL_SET_SPARSE   	- делает файл sparse

    FSCTL_SET_ZERO_DATA	- устанавливает дырки в файле

    FSCTL_QUERY_ALLOCATION_RANGE - говорит какие части не sparse

    ------------------------------------------
    FSCTL_SET_SPARCE		(Win2000+)

        lpInBuffer:	NULL
        lpOutBuffer:	NULL
    -------------------------------------------
    FSCTL_QUERY_ALLOCATION_RANGES	(Win2000+)

        lpInBuffer:
            FILE_ALLOCATION_RANGE_BUFFER
        lpOutBuffer:
            FILE_ALLOCATION_RANGE_BUFFER
        typedef struct _FILE_ALLOCATED_RANGE_BUFFER
        {
                LARGE_INTEGER FileOffset;
                LARGE_INTEGER Length;
        } FILE_ALLOCATED_RANGE_BUFFER;

    ---------------------------------------------
    FSCTL_SET_ZERO_DATA		(Win2000+)
        lpInBuffer:
            FILE_ZERO_DATA_INFORMATION
        lpOutBuffer: NULL
        typedef struct _FILE_ZERO_DATA_INFORMATION
        {
                LARGE_INTEGER FileOffset;
                LARGE_INTEGER BeyondFinalZero;
        } FILE_ZERO_DATA_INFORMATION;
    ---------------------------------------------

// Пример создания sparse file

HANDLE h = CreateFile("SparseFile",
                  GENERIC_WRITE,
                  0,
                  NULL,
                  CREATE_ALWAYS,
                  0,
                  NULL);
    DWORD dw;
    DeviceIoControl(h,FSCTL_SET_SPARSE,NULL,0,NULL,0,&dw,NULL);
    LONG  high = 16;
    SetFilePointer(h,0,&high,FILE_BEGIN);	// means 10 0000 0000 length
    SetEndOfFile(h);
    CloseHandle(h);

  Multiple streams

Собственно некоторый файловые системы позволяют иметь больше одного data stream в файле.
Например NTFS позволяет иметь сколько хочешь data streams, главное что бы они отличались
именами + один data stream основной не имеет имени.

Операции для работы с data streams такие же как обычные файловые операции, просто
имя файла для потока выгляди так:

    D:\DIR\SUBDIR\FILENAME.EXT:STREAM_NAME

Но собственно возникает вопрос с энумерацией потоков.

 Windows

// Vista+
HANDLE WINAPI FindFirstStreamW(LPCWSTR lpFileName,
                     STREAM_INFO_LEVELS InfoLevel, // FileStreamInfoStandard
                   LPVOID lpFindStreamData,
                   DWORD dwFlags);

BOOL WINAPI FindNextStreamW(HANDLE hFindStream,
                LPVOID lpFindStreamData);

BOOL WINAPI FindClose(HANDLE hFindFile);

typedef struct _WIN32_FIND_STREAM_DATA
{
    LARGE_INTEGER StreamSize;
    WCHAR cStreamName[MAX_PATH + 36];
} WIN32_FIND_STREAM_DATA,  *PWIN32_FIND_STREAM_DATA;

  Encrypted Files

Управление состоянием файла:

 Windows

BOOL WINAPI EncryptFile(
  __in          LPCTSTR lpFileName
);

BOOL WINAPI DecryptFile(
  __in          LPCTSTR lpFileName,
         DWORD dwReserved
);

BOOL WINAPI FileEncryptionStatus(
  __in          LPCTSTR lpFileName,
  __out         LPDWORD lpStatus
);

    // *lpStatus is
    //	FILE_ENCRYPTABLE
    //	FILE_IS_ENCRYPTED
    //	FILE_READ_ONLY
    //	FILE_ROOT_DIR
    //	FILE_SYSTEM_ATTR
    //	FILE_SYSTEM_DIR
    //	FILE_SYSTEM_NOT_SUPPORT
    //	FILE_UNKNOWN
    //	FILE_USER_DISALLOWED

Управление пользователями которые имеют доступ к
encrypted file:

 Windows

DWORD WINAPI AddUsersToEncryptedFile(
  __in          LPCWSTR lpFileName,
  __in          PENCRYPTION_CERTIFICATE_LIST pUsers
);

DWORD WINAPI QueryUsersOnEncryptedFile(
  __in          LPCWSTR lpFileName,
  __out         PENCRYPTION_CERTIFICATE_HASH_LIST* pUsers
);

DWORD WINAPI RemoveUsersFromEncryptedFile(
  __in          LPCWSTR lpFileName,
  __in          PENCRYPTION_CERTIFICATE_HASH_LIST pHashes
);

void WINAPI FreeEncryptionCertificateHashList(
  __in          PENCRYPTION_CERTIFICATE_HASH_LIST pHashes
);

DWORD WINAPI SetUserFileEncryptionKey(
  __in          PENCRYPTION_CERTIFICATE pEncryptionCertificate
);

Backup интерфейс к encrypted files:

 Windows

DWORD WINAPI OpenEncryptedFileRaw(
  __in          LPCTSTR lpFileName,
  __in          ULONG ulFlags,
  __out         PVOID* pvContext
);

void WINAPI CloseEncryptedFileRaw(
  __in          PVOID pvContext
);

DWORD WINAPI ReadEncryptedFileRaw(
  __in          PFE_EXPORT_FUNC  pfExportCallback,
  __in          PVOID pvCallbackContext,
  __in          PVOID pvContext
);

DWORD WINAPI WriteEncryptedFileRaw(
  __in          PFE_IMPORT_FUNC pfImportCallback,
  __in          PVOID pvCallbackContext,
  __in          PVOID pvContext
);

DWORD WINAPI ImportCallback(
  [in]                 PBYTE pbData,
  [in]                 PVOID pvCallbackContext,
  [in, out]            PULONG ulLength
);

DWORD WINAPI ExportCallback(
  [in]                 PBYTE pbData,
  [in]                 PVOID pvCallbackContext,
  [in]                 ULONG ulLength
);

Управление encrypted директориями:

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

 Windows

BOOL WINAPI EncryptionDisable(		// только флаг для директорий
  __in          LPCWSTR DirPath,
  __in          BOOL Disable
);

  Object ID

Возможность быстрого открытия файла не по пути а по уникальному GUID -
Object ID.
(Естественно надо иметь права на bypass directory traverse для этой
операции)

    --------------------------------------------------
    FSCTL_CREATE_OR_GET_OBJECT_ID		(Win2000+)
    lpInBuffer:	NULL
    lpOutBuffer:	PFILE_OBJECTID_BUFFER
    typedef struct _FILE_OBJECTID_BUFFER
    {
        BYTE ObjectId[16];
          union
        {
                  struct
            {
                      BYTE  BirthVolumeId[16];
                      BYTE  BirthObjectId[16];
                      BYTE  DomainId[16];
                  };
                BYTE  ExtendedInfo[48];
          };
    } FILE_OBJECTID_BUFFER, *PFILE_OBJECTID_BUFFER;

    --------------------------------------------------
    FSCTL_SET_OBJECT_ID		(Win2000+)
    lpInBuffer:	PFILE_OBJECTID_BUFFER
    lpOutBuffer:	NULL
    --------------------------------------------------
    FSCTL_GET_OBJECT_ID		(Win2000+)
    lpInBuffer:	NULL
    lpOutBuffer:	PFILE_OBJECTID_BUFFER
    ---------------------------------------------------
    FSCTL_DELETE_OBJECT_ID		(Win2000+)
    lpInBuffer:	NULL
    lpOutBuffer:	NULL
    ---------------------------------------------------
    FSCTL_SET_OBJECT_ID_EXTENDED	(Win2000+)
    lpInBuffer:	PFILE_OBJECTID_BUFFER
    lpOutBuffer:	NULL
    ----------------------------------------------------

  Временные файлы

Хотя в общем то это не интерфейс для файловой системы, а скорее все таки
для операционной системы:

 Windows

UINT WINAPI GetTempFileName(
      __in          LPCTSTR lpPathName,
      __in          LPCTSTR lpPrefixString,
      __in          UINT uUnique,
      __out         LPTSTR lpTempFileName);

DWORD WINAPI GetTempPath(
      __in          DWORD nBufferLength,
      __out         LPTSTR lpBuffer);

 UNIX

// stdio.h

char *tmpnam(char *s);
char *tempnam(const char *dir, const char *pfx);
FILE *tmpfile (void);			// это уже стандартная библиотека

char *mktemp(char *template);		// stdlib.h
int   mkstemp(char *template);		// stdlib.h

char *mkdtemp(char *template);		// temp directory stdlib.h


81.3.3.4.1. РАБОТА С БОЛЬШИМИ ФАЙЛАМИ

THIS SECTION IS UNDER CONSTRUCTION

Собственно размеры storage растут, и допустимые размеры файлов тоже.
Произошел переход с 32-битного размера файлов на 64-битный.

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

Специальные 64-бит варианты функций
    флаги для open
    ftruncate64
    lstat64
    pwrite64
    pread64
    stat64
    statvfs64
    creat64
    fstat64
    fstatvfs64
    lseek64/llseek
    open64

Потом свели интерфейс к классическому определив тип off_t - смещение в файле
Для совместимости ввели макрос который говорит использовать ли 32-бит или
64-бит API.

 UNIX

// Linux, unistd.h

#ifndef __USE_FILE_OFFSET64
extern __off_t lseek (int __fd, __off_t __offset, int __whence) __THROW;
#else
# ifdef __REDIRECT_NTH
extern __off64_t __REDIRECT_NTH (lseek,
                 (int __fd, __off64_t __offset, int __whence),
                 lseek64);
# else
#  define lseek lseek64
# endif
#endif
#ifdef __USE_LARGEFILE64
extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
     __THROW;
#endif

64bit file access

    _FILE_OFFSET_BITS

    statfs
    statfs64
    fstatfs
    fstatfs64

    pivot_root

    getdents
    getdents64

    lookup_dcookie

    chown16
    lchown16
    fchown16

    oldstat
    oldfstat
    oldlstat

    stat64
    lstat64
    fstat64

    fcntl64

    ftruncate64
    _llseek

    sendfile
    sendfile64

    pread64
    pwrite64

int ftruncate64(int fildes, off64_t length);

int open64(const char *pathname, int oflag,...);
    open() with O_LARGEFILE


81.3.3.4.2. MEMORY-MAPPED ФАЙЛЫ

THIS SECTION IS UNDER CONSTRUCTION

Об API для работы с memory-mapped files можно прочитать в секции
81.2.4. ПАМЯТЬ С ТОЧКИ ЗРЕНИЯ ПРИЛОЖЕНИЙ
Там же рассматриваются Memory аспекты memory mapped files

В этой секции рассматриваются file-system аспекты memory-mapped files.

Собственно с файлами можно паралельно работать и обычными файловыми API,
и memory-mapped API.

Особенности Windows:
Когда вы делаете CreateFileMapping, вы указываете Maximum File Size для Mappingа.
На закрытие вы получите файл такого же размера  как Maximum file size или больше (если
вы писали например стандартными файловыми функциями  дальше).

Еще особый случай WOW64 - надо использовать GetNativeSystemInfo().

  Выравнивание начала mapping

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

Для UNIX систем - это как правило страница. Соответсвенно выравнивание можно получить:

 UNIX

// unistd.h
int	getpagesize();

Если getpagesize() в вашем UNIX не реализовано то можно попробывать:
    sysconf(_SC_PAGESIZE);
или	sysconf(_SC_PAGE_SIZE);

Для Windows систем все хуже - несмотря на то что система мапирует страницами, но
регионы она берет через VAD. Поэтому нужно выравнивание на VAD регион.
Обычно это 64K, но более правильно будет все таки использовать API:

 Windows

void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);

typedef struct _SYSTEM_INFO
{
    union
    {
        DWORD dwOemId;
        struct
        {
            WORD wProcessorArchitecture;
            WORD wReserved;
        };
    };
    DWORD dwPageSize;
    LPVOID lpMinimumApplicationAddress;
    LPVOID lpMaximumApplicationAddress;
    DWORD_PTR dwActiveProcessorMask;
    DWORD dwNumberOfProcessors;
    DWORD dwProcessorType;
    DWORD dwAllocationGranularity;  // этот поле надо использовать для выравнивания
    WORD wProcessorLevel;
    WORD wProcessorRevision;
} SYSTEM_INFO;

void WINAPI GetNativeSystemInfo(
  __out         LPSYSTEM_INFO lpSystemInfo
);

  Сайд-эффекты в конце mapping

Если длинна вашего маппинга выравнена по границе страницы (она не обязана быть выравненой) -
то у вас все хорошо. В противном случае есть ньюансы.

Собственно система смотрит за тем что бы при записи в файл передовалась только та часть
последней страницы которая была заявлена в mapping.

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

    UNIX будет занулять tail последней страницы
    Windows не будет занулять tail последней страницы


81.3.3.5. КОНЦЕПТУАЛЬНЫЙ RTL РАБОТЫ С ФАЙЛАМИ

Концептуальный RTL для файлов

    Создание и/или открытие файла
        на чтение
        на запись
        на добавление
            file pointer ставиться на конец

        создавать только если не существует
        создавть всегда (если есть старый то заменяем его)
        открыть существующий
        открыть существующий, создать если нет
        если существует - усечь до нулевой длинны

    Аттрибуты при создании
    Режим sharing
        share read
        share write
        share all
    Режим caching
        write through
        no buffering
    Cache hints
        sequental access
        random access
    Режим временного файла
        delete on close
    Synchronous I/O
    Разрешить ассинхронный I/O

    Закрыть файл

    Чтение из файла (общее)
        Буфер
        Смещение в файле
        Количество байт
        Количество байт сколько прочиталось

    Запись в файл

    Асинхронные варианты чтения/записи

    Seek file (Set file pointer)

    Сбросить буфера файла на диск

    Залочить/Анлочить файл/регион в файле

    Получить размер файла

    Получить/установить аттрибуты файла

    Получить/установить времена файла

    Удалить файл
    Переименовать файл
    Переместить файл
    Скопировать файл

Пользовательский RTL для файлов
    например - считать строку из файла
    Обвязки - файлы и сокеты бывают разными объектами

Windows API:
    CreateFile
    CloseHandle
    DeleteFile
    WriteFile
    FlushFileBuffers
    ReadFile
    SetFilePointer
    SetFilePointerEx
    GetFileAttributes
    SetFileAttributes
    GetFileSize
    GetFileSizeEx
    SetEndOfFile

    LockFile
    UnlockFile
    GetFileInformationByHandle

    CopyFile
    MoveFile
    ReplaceFile

    ReadFileEx
    WriteFileEx
    CancelIo

MemoryMapped:
    CreateFileMapping
    OpenFileMapping
    MapViewOfFile
    MapViewOfileEx
    UnmapViewOfFile
    FlushViewOfFile

UNIX API:
    open
    creat
    close
    umask
    unlink
    read
    write
    lseek  и его варианты
    pread
    pwrite
    readv
    writev

    sync
    fsync
    fdatasync

    truncate
    ftruncate
    rename

    stat
    fstat

    chmod
    fchmod
    chown
    fchown
    utime
    access
    fcntl


81.3.3.6. ДИРЕКТОРИИ

API для директорий

  Создание и удаление

Операции с директориями:

    создать директорию

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

На самом деле очень интересно посмотреть как работала библиотечная функция по
созданию директории в ранней версиях UNIX:
    Она создавала специальный файл - типа директория
    Затем делала hard link на саму директорию и на родителя
    (если только он на root) с именами . и ..
    Поэтому даже сейчас UNIX позволяет делать hardlinks на директории.

 UNIX

int	mkdir(const char* path, mode_t mode)
int	rmdir(const char* path)

int   remove(const char* path);  // C   удаляет file или dir

 Windows

BOOL WINAPI CreateDirectory(
  __in          LPCTSTR lpPathName,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

BOOL WINAPI CreateDirectoryEx(
  __in          LPCTSTR lpTemplateDirectory,
  __in          LPCTSTR lpNewDirectory,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

BOOL WINAPI RemoveDirectory(
  __in          LPCTSTR lpPathName
);

  Обход директории

    Собственно два основных типа запросов
        Искать все
        Искать по маске

    обход директории
        FindFirst/FindNext/FindClose/FindRewind 2 уровней

 UNIX

DIR*	opendir(const char*name)
int	dirfd(DIR* dir)			// BSD
struct dirent * readdir(DIR* dir)
int	closedir(DIR* dir)

    // . and .. in directory not warranted
    // may absent or be in center of catalog

struct	direct
{
    ino_t	d_ino;					// UNIX, d_fileno
    off_t	d_off;	// offset to next record
    unsigned short d_reclen;
    unsigned char  d_type;  			// Linix,BSD
            DT_BLK
            DT_CHR
            DT_DIR
            DT_FIFO
            DT_LNK
            DT_REG
            DT_SOCK
            DT_UNKNOWN
            DT_WHT    		// bsd
    char	d_name[256];                           //+
};

void	rewinddir(DIR* dir)		// Non standard

int	readdir(int	fd, struct dirent* dirp, unsigned int count); 	// internal
int	getdirents(int fd, struct dirent* dirp, unsigned int count);	// internal
int	readdir_r(DIR* restrict dir, struct dirent* entry, struct dirent** result)

readdir() - thread небезопасная функция, потому что struct dirent* которую она
возвращает разделяется всем процессом. И в мультизадачной среде могут быть проблемы.
Решение - использовать readdir_r, или написать аналогичную обвязку.

Не все системы поддерживают telldir/seekdir. Вообще эти функции возникли в то время
когда в UNIX использовалась только одна файловая система, и она имела записи в
директории фиксированной длинны. Длинна имени файла была фиксированная и небольшая.
Поэтому действия этих функций были аналогичны функции lseek().
А в настоящее время у нас куча файловых систем, многие из которых директорию держат
не последовательно а в виде деревьев, соответсвенно реалтизация этих функций сильно
затрудненa.

 UNIX

void	seekdir(DIR* dir, long loc)     // Non standard  BSD
long	telldir(DIR* dir)		// Non standard  BSD

 UNIX

// dirent.h  BSD

int  dirfd(DIR* dir);   // получение fd для директории

shell еще использует функции для того чтобы проверить подходит ли имя под
wildcards:

 UNIX

// fnmatch.h

int fnmatch(const char *pattern, const char *string, int flags);
    FNM_NOESCAPE
    FNM_PATHNAME
    FNM_PERIOD
    FNM_FILE_NAME
    FNM_LEADING_DIR
    FNM_CASEFOLD

 UNIX

// glob.h

int glob(const char *pattern, int flags,
         int errfunc(const char *epath, int eerrno),
         glob_t *pglob);

void globfree(glob_t *pglob);

 Windows

HANDLE WINAPI FindFirstFile(
  __in          LPCTSTR lpFileName,
  __out         LPWIN32_FIND_DATA lpFindFileData
);

BOOL WINAPI FindNextFile(
  __in          HANDLE hFindFile,
  __out         LPWIN32_FIND_DATA lpFindFileData
);

BOOL WINAPI FindClose(
  __in_out      HANDLE hFindFile
);

typedef struct _WIN32_FIND_DATA
{
    DWORD dwFileAttributes;
        // FILE_ATTRIBUTE_ARCHIVE
        // FILE_ATTRIBUTE_COMPRESSED
        // FILE_ATTRIBUTE_DIRECTORY
        // FILE_ATTRIBUTE_ENCRYPTED
        // FILE_ATTRIBUTE_HIDDEN
        // FILE_ATTRIBUTE_NORMAL		// file or dir w/o other attributes set
        // FILE_ATTRIBUTE_NO_CONTEXT_INDEXED
        // FILE_ATTRIBUTE_OFFLINE
        // FILE_ATTRIBUTE_READONLY
        // FILE_ATTRIBUTE_REPARSE_POINT
        // FILE_ATTRIBUTE_SPARSE_FILE
        // FILE_ATTRIBUTE_SYSTEM
        // FILE_ATTRIBUTE_TEMPORARY
        // FILE_ATTRIBUTE_VIRTUAL
    FILETIME ftCreationTime;
    FILETIME ftLastAccessTime;
    FILETIME ftLastWriteTime;
    DWORD nFileSizeHigh;
    DWORD nFileSizeLow;
    DWORD dwReserved0;
    DWORD dwReserved1;
    TCHAR cFileName[MAX_PATH];
    TCHAR cAlternateFileName[14];
} WIN32_FIND_DATA,  *PWIN32_FIND_DATA,  *LPWIN32_FIND_DATA;

  Hard Links на директории

Собственно UNIX с незапамятных времен позволяет делать hardlinks на директории.
Это связано с тем, что в ранних версиях UNIX не было системного вызова mkdir,
вместо него была библиотечная функция mkdir(), которая делала следущее
    1) создавала специальный файл директории с помощью системного вызова mknod
    2) создавала в этой новой директории жесткие ссылки на саму же директорию
           и на родительскую директорию с помощью вызова link, с именами . и ..
       соответсвенно.

В наше время жесткие ссылки на директорию тоже используются, например Apple TimeMachine
(один из компонентов Mac OS X [начиная с 10.5 Leopard]) использует такие ссылки.

Windows не поддерживает hardlinks на директории.

  Текущая директория

Операции с текущей директорией

        выбрать текущую директорию

    получить текущую директорию

 UNIX

char*	getcwd(char* buf, size_t size);
int	chdir(const char* path);
int	fchdir(int fd);	// by handle - предвырительно директория должна
            // быть отрыта через open() с флагом O_DIRECTORY

 Windows

DWORD WINAPI GetCurrentDirectory(
            DWORD nBufferLength,
            LPTSTR lpBuffer);

BOOL WINAPI SetCurrentDirectory(
           LPCTSTR lpPathName);

    Для систем с некорневыми файловыми системами это еще возможна и per volume,
    либо другими специальными способами (смотри секцию РАБОТА С ПУТЯМИ ниже)

Windows:
Нужно обратить внимание на то что еще есть текущие директории на отдельных дисках.
Они храняться в Environment variables процесса как переменные с именами:
        =D:

внутри envrionment variable area это выглядет как:
    =C:=C:\Dir
    =D:=D:\Program Files

Windows функции могут с ними работать, но они их не ставят, это делает cmd,
или ели надо для потомков, то приходиться делать ручками.

Получить текущий каталог для указанного диска можно:

    GetFullPathName("C:", MAX_PATH, szBuf, NULL)

 Windows

DWORD WINAPI GetFullPathName(
      __in          LPCTSTR lpFileName,
      __in          DWORD nBufferLength,
      __out         LPTSTR lpBuffer,
      __out         LPTSTR* lpFilePart);

// 3rd party нестандартные расширения

// dirent.h
char* _getdcwd(int drive, char* buffer, int buflen);
int   _chdrive(int drive);
int   _getdrive(void);

// dir.h
int   getcurdir(int drive, char* directory);
int   getdisk(void);
int   setdisk(int drive);

  Нотификация об изменениях в директории

    нотификации о изменениях в директории

        настроить

        получить изменения

        закрыть

//Linux  (старый вариант)

    open() директорию

    fcntl(fd, F_NOTIFY, &flags)

    // flags:
    //	DN_ACCESS
    //	DN_ATTRIB
    //	DN_CREATE
    //	DN_DELETE
    //	DN_NOTIFY
    //	DN_RENAME

    //	DN_MULTISHOT покрывает все

При возникновении события вызывается сигнал SIGIO

 UNIX

// Linux (новый вариант)
// inotify.h

int	inotify_init(void);	// получаем notify handle
int	inotify_add_watch(int fd, const char* path, uint32_t mask);
                // возращает watchdog descriptor
        IN_ACCESS
        IN_MODIFY
        IN_ATTRIB
        IN_CLOSE_WRITE
        IN_CLOSE_NOWRITE
        IN_OPEN
        IN_MOVED_FROM
        IN_MOVED_TO
        IN_CREATE
        IN_DELETE
        IN_DELETE_SELF
        IN_MOVE_SELF

int	inotify_rm_watch(int fd, uint32_t wd)

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

struct inotify_event
{
    int		wd;	// watchdog descriptor
    uint32_t	mask;
    uint32_t	cookie;
    uint32_t	len;
    char		name[];
};

Потом notify handle закрывается с помощью простого close()

 Windows

HANDLE WINAPI FindFirstChangeNotification(
  __in          LPCTSTR lpPathName,
  __in          BOOL bWatchSubtree,
  __in          DWORD dwNotifyFilter);

    // dwNotifyFilter is:
    //	FILE_NOTIFY_CHANGE_FILE_NAME
    //	FILE_NOTIFY_CHANGE_DIR_NAME
    //	FILE_NOTIFY_CHANGE_ATTRIBUTES
    //	FILE_NOTIFY_CHANGE_SIZE
    //	FILE_NOTIFY_CHANGE_LAST_WRITE
    //	FILE_NOTIFY_CHANGE_LAST_ACCESS
    //	FILE_NOTIFY_CHANGE_SECURITY

BOOL WINAPI FindNextChangeNotification(
  __in          HANDLE hChangeHandle);

BOOL WINAPI FindCloseChangeNotification(
  __in          HANDLE hChangeHandle);

BOOL WINAPI ReadDirectoryChangesW(
  __in          HANDLE hDirectory,
  __in_out      LPVOID lpBuffer,		// FILE_NOTIFY_INFORMATION
  __in          DWORD nBufferLength,
  __in          BOOL bWatchSubtree,
  __in          DWORD dwNotifyFilter,
  __out         LPDWORD lpBytesReturned,
  __in          LPOVERLAPPED lpOverlapped,
  __in          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

typedef struct _FILE_NOTIFY_INFORMATION
{
    DWORD NextEntryOffset;
    DWORD Action;
        // FILE_ACTION_ADDED
        // FILE_ACTION_REMOVED
        // FILE_ACTION_MODIFIED
        // FILE_ACTION_RENAMED_OLD_NAME
        // FILE_ACTION_RENAMED_NEW_NAME
    DWORD FileNameLength;
    WCHAR FileName[1];
} FILE_NOTIFY_INFORMATION,  *PFILE_NOTIFY_INFORMATION

 Windows

NTSTATUS NTAPI NtNotifyChangeDirectoryFile(
    IN	HANDLE	FileHandle,
    IN	HANDLE	Event	OPTIONAL,
    IN	PIO_APC_ROUTINE   ApcRoutine OPTIONAL,
    IN	PVOID		  ApcContext OPTIONAL,
    OUT	PIO_STATUS_BLOCK  IoStatusBlock,
    OUT	PFILE_NOTIFY_INFORMATION  Buffer,
    IN	ULONG	BufferLength,
    IN	ULONG	NotifyFilter,
    IN	BOOLEAN WatchSubtree);

Notify filter is:
    FILE_NOTIFY_CHANGE_FILE_NAME	add/delete or rename
    FILE_NOTIFY_CHANGE_DIR_NAME
    FILE_NOTIFY_CHANGE_NAME
    FILE_NOTIFY_CHANGE_ATTRIBUTES
    FILE_NOTIFY_CHANGE_SIZE
    FILE_NOTIFY_CHANGE_LAST_WRITE
    FILE_NOTIFY_CHANGE_LAST_ACCESS
    FILE_NOTIFY_CHANGE_CREATION
    FILE_NOTIFY_CHANGE_EA
    FILE_NOTIFY_CHANGE_SECURITY
    FILE_NOTIFY_CHANGE_STREAM_NAME
    FILE_NOTIFY_CHANGE_STREAM_SIZE
    FILE_NOTIFY_CHANGE_STREAM_WRITE

  Структура директорий

В Novell Netware возможно управление дисковыми квотами не только на уровне
диска, но и на уровне директории.

Организация директории

    Список записей фиксированного размера
        FAT
        в некоторых случаях может быть использовано больше 1й записи

    Список записей переменного размера
        При удалении
            дырка
            уплотнение
        Граница кластера
            может пересекаться записью
            не может пересекаться записью  (padding в конце блока)
        Блоки могут иметь заголовок, а могут и не иметь.

    Дерево
        NTFS
        Апофеоз - ReiserFS 3.x - где все данные на диске входят
        в одно единственное дерево

    Список inode
        Amiga FFS
            в случае жесткой ссылки она указывает на файл/dir
            который может находиться в другой директории

Что храниться в директории
    Всегда:
        Имя
        указатель на inode
    Может храниться:
        Некоторые базовые аттрибуты (типа файл или директория)
        Длинна файла

  Что происходит в реальности?

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

 Windows

NTSYSAPI NTSTATUS NTAPI NtQueryDirectoryFile(
        IN HANDLE FileHandle,
        IN HANDLE Event OPTIONAL,
        IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
        IN PVOID ApcContext OPTIONAL,
        OUT PIO_STATUS_BLOCK IoStatusBlock,
        OUT PVOID FileInformation,
        IN  ULONG FileInformationLength,
        IN FILE_INFORMATION_CLASS  FileInformationClass,   // FileBothDirectoryInformation
        IN BOOLEAN ReturnSingleEntry,		// отдавать ли сразу много entries
        IN PUNICODE_STRING  FileName OPTIONAL,	// маска
        IN BOOLEAN RestartScan);

typedef  struct _FILE_BOTH_DIRECTORY_INFORMATION
{
    ULONG	NextEntryOffset;		// указатель на следущий entry
    ULONG	Unknown;
    LARGE_INTEGER	CreationTime;
    LARGE_INTEGER	LastAccessTime;
    LARGE_INTEGER	LastWriteTime;
    LARGE_INTEGER	ChangeTime;
    LARGE_INTEGER	EndOfFile;
    LARGE_INTEGER	AllocationSize;
    ULONG	FileAttributes;
    ULONG	FileNameLength;
    ULONG	EaInformationLength;
    UCHAR	AlternativeNameLength;
    WCHAR	AlternativeName[12];
    WCHAR	FileName[1];
} FILE_BOTH_DIRECTORY_INFORMATION;

 UNIX

// Linux
//	собственно сам системный вызов

int getdents(unsigned int fd, struct dirent *dirp, unsigned int count);

    // count - количество байт в области памяти
    // возвращает: количество байтов, которые использовали

struct dirent
{
        long 	d_ino;                 /* inode number */
        off_t 	d_off;                 /* offset to next dirent */
        unsigned short d_reclen;       /* length of this dirent */
        char 	d_name [NAME_MAX+1];   /* filename (null-terminated) */
}

На самом деле поиск по директории реально pain in the ass для File system drivers.
Потому что в промежутках между запросами связанными с одним поиском по директории
внутри директории может происходить куча вещей - файлы могут создаваться, удаляться
итд итп. А FSD все равно должен осуществлять продолжение поиска.

  glob API

UNIX имеет glob API которые используются shell, для выбора имен файлов
по шаблону (не Regular expressions, а просто wildcards).

Собственно какие wildcards поддерживает glob:

    ?
    *
    [char_class]

#include <glob.h>

int  glob(const char *pattern, int flags,
          const int (*errfunc)(const char *, int), glob_t *pglob);

    // flags is:
    //	GLOB_APPEND
    //	GLOB_DOOFFS
    //	GLOB_ERR
    //	GLOB_MARK
    //	GLOB_NOCHECK
    //	GLOB_NOSORT

void globfree(glob_t *pglob);

typedef struct {
             int gl_pathc;           /* count of total paths so far */
             int gl_matchc;          /* count of paths matching pattern */
             int gl_offs;            /* reserved at beginning of gl_pathv */
             int gl_flags;           /* returned flags */
             char **gl_pathv;        /* list of paths matching pattern */
     } glob_t;

//	Пример что делает shell получая команду 'ls -l *.c *.h'

    glob_t g;
        g.gl_offs = 2;
        glob("*.c", GLOB_DOOFFS, NULL, &g);
        glob("*.h", GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
        g.gl_pathv[0] = "ls";
        g.gl_pathv[1] = "-l";
        execvp("ls", g.gl_pathv);

  ftw интерфейс

 UNIX

// UNIX
// 	ftw.h

int  ftw(const char* dir, ftwFunctionPointer callback, int depth);

int  ftwCallBackFunction(const char* file, const struct stat * sb, int flags);
    // flags are:
    //	FTW_F		file or (symlink to file)
    //	FTW_D		directory or (symlink to dir0
    //	FTW_DNR		нельзя войти в директорию
    //	FTW_SL		symbolic link
    //	FTW_NS		no stat info available

 UNIX

// UNIX

int nftw(const char* dir, nftwFunctionPointer callback, int depth, int flags);

int nftwCallbackFunction(const char* file, const struct stat* sb,
             int flags, struct FTW* ftws);

  scandir интерфейс

Читает всю директорию в память и сортирует ее.

 UNIX

// dirent.h BSD

int scandir(const char* dir, struct dirent*** namelist,
        int (*select)(const struct dirent*),
        int (*compare)(consgt struct dirent**, const struct dirent**));

int alphasort(const void* a, const void* b);
int versionsort(const void* a, const void* b);

    strverscmp


81.3.3.7. ТРАНЗАКЦИОННЫЕ ОПЕРАЦИИ

THIS SECTION IS UNDER CONSTRUCTION

Зачем это надо?

Типовая работа с документами
        Открыли файл на чтение
        Создали его копию для записи
        Ее обновили
        Файл переменовали в предидущий

Windows начиная с Vista поддерживает TxF (Transactional NTFS).
Смысл в том, что группа операций на файловой системе работает как транзакция
(или все успешно, или ничто не выполненно).

HANDLE WINAPI CreateFileTransacted(
  __in          LPCTSTR lpFileName,
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwShareMode,
  __in_opt      LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  __in          DWORD dwCreationDisposition,
  __in          DWORD dwFlagsAndAttributes,
  __in_opt      HANDLE hTemplateFile,
  __in          HANDLE hTransaction,
  __in_opt      PUSHORT pusMiniVersion,
  PVOID pExtendedParameter
);

HANDLE WINAPI FindFirstFileNameTransactedW(
  __in          LPCWSTR lpFileName,
  __in          DWORD dwFlags,
  __in_out      LPDWORD StringLength,
  __in_out      PWCHAR LinkName,
  __in_opt      HANDLE hTransaction
);

HANDLE WINAPI FindFirstStreamTransactedW(
  __in          LPCWSTR lpFileName,
  __in          STREAM_INFO_LEVELS InfoLevel,
  __out         LPVOID lpFindStreamData,
  DWORD dwFlags,
  __in          HANDLE hTransaction
);

BOOL WINAPI GetFileAttributesTransacted(
  __in          LPCTSTR lpFileName,
  __in          GET_FILEEX_INFO_LEVELS fInfoLevelId,
  __out         LPVOID lpFileInformation,
  __in          HANDLE hTransaction
);

BOOL WINAPI SetFileAttributesTransacted(
  __in          LPCTSTR lpFileName,
  __in          DWORD dwFileAttributes,
  __in          HANDLE hTransaction
);

BOOL WINAPI CreateHardLinkTransacted(
  __in          LPCTSTR lpFileName,
  __in          LPCTSTR lpExistingFileName,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  __in          HANDLE hTransaction
);

BOOL WINAPI CreateSymbolicLinkTransacted(
  __in          LPCWSTR lpSymlinkFileName,
  __in          LPCWSTR lpTargetFileName,
  __in          DWORD dwFlags,
  __in          HANDLE hTransaction
);

BOOL WINAPI DeleteFileTransacted(
  __in          LPCTSTR lpFileName,
  __in          HANDLE hTransaction
);

BOOL WINAPI CreateDirectoryTransacted(
  __in_opt      LPCTSTR lpTemplateDirectory,
  __in          LPCTSTR lpNewDirectory,
  __in_opt      LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  __in          HANDLE hTransaction
);

BOOL WINAPI RemoveDirectoryTransacted(
  __in          LPCTSTR lpPathName,
  __in          HANDLE hTransaction
);

HANDLE WINAPI FindFirstFileTransacted(
  __in          LPCTSTR lpFileName,
  __in          FINDEX_INFO_LEVELS fInfoLevelId,
  __out         LPVOID lpFindFileData,
  __in          FINDEX_SEARCH_OPS fSearchOp,
  LPVOID lpSearchFilter,
  DWORD dwAdditionalFlags,
  __in          HANDLE hTransaction
);

BOOL WINAPI MoveFileTransacted(
  __in          LPCTSTR lpExistingFileName,
  __in          LPCTSTR lpNewFileName,
  __in          LPPROGRESS_ROUTINE lpProgressRoutine,
  __in          LPVOID lpData,
  __in          DWORD dwFlags,
  __in          HANDLE hTransaction
);

BOOL WINAPI CopyFileTransacted(
  __in          LPCTSTR lpExistingFileName,
  __in          LPCTSTR lpNewFileName,
  __in_opt      LPPROGRESS_ROUTINE lpProgressRoutine,
  __in_opt      LPVOID lpData,
  __in_opt      LPBOOL pbCancel,
  __in          DWORD dwCopyFlags,
  __in          HANDLE hTransaction
);


81.3.3.8. QOS ДЛЯ ФАЙЛОВОГО ВВОДА/ВЫВОДА

THIS SECTION IS UNDER CONSTRUCTION

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

 Windows

// Vista+

BOOL WINAPI GetFileBandwidthReservation(
  __in          HANDLE hFile,
  __out         LPDWORD lpPeriodMilliseconds,
  __out         LPDWORD lpBytesPerPeriod,
  __out         LPBOOL pDiscardable,
  __out         LPDWORD lpTransferSize,
  __out         LPDWORD lpNumOutstandingRequests
);

BOOL WINAPI SetFileBandwidthReservation(
  __in          HANDLE hFile,
  __in          DWORD nPeriodMilliseconds,
  __in          DWORD nBytesPerPeriod,
  __in          BOOL bDiscardable,
  __out         LPDWORD lpTransferSize,
  __out         LPDWORD lpNumOutstandingRequests
);


81.3.3.9. ОШИБКИ ПРИ РАБОТЕ С ФАЙЛАМИ

THIS SECTION IS UNDER CONSTRUCTION

EACCESS		нет разрешения на доступ к одному из каталогов
EBADF		bad filehandle
ELOOP		путь содержит слишком много symlinks
ENAMETOOLONG	слишком длинный path
ENOENT		компонент пути не существуект
ENOMEM
ENOTDIR
EIO
EPERM		euid не соответсвует владельцу файла
EROFS
ENOATTR
ENOTSUP		fs не поддерживает данную feature
EDQUOT
EEXIST
EINVAL		неправильные флаги
ENOSPC
ENOTEMPTY
EMLINK		maximum link counter reacheed
EXDEV		разные устройства
EISDIR
EFBIG		файл больше максимального размера
EOVERFLOW	file offset overflow
ENFILE		достигнут предел по количеству открытых файлов


81.3.4.1. РАБОТА С ПУТЯМИ

Разделители путей

    \	Windows (но она понимает и /)
    /	UNIX
    :	Mac

Примеры
    A:\DIRNAME\DIRNAME\FILENAME.EXT			// DOS
    C:\DIRNAME\DIRNAME\FILENAME.EXT:STREAMNAME	// Windows NT
    /DIRNAME/DIRNAME/FILENAME.EXT  			// UNIX
    VOLNAME:DIRNAME:DIRNAME:FILENAME.EXT		// MacOS
    VOLNAME:\DIRNAME\DIRNAME\FILENAME.EXT		// Netware
    VOLNAME:\DIRNAME\DIRANEM\FILENAME.EXT;VER       // VMS

Разделители групп путей

    set PATH=C:\WINDOWS;C:\BIN		; 	Windows
    set PATH=/share/bin:/usr/shar/bin	:	UNIX

Работа с путями к объектам файловой системы как правило недоступна в библиотеках
языков программирования среднего уровня. Поэтому необходимый RTL приходиться
писать программистам самим.

Собственно есть 3 группы путей:
1) Полностью квалифицированные пути

    C:\My Documents\myfile.txt	// Windows Local Filesystem
    \\SERVER\Share\myfile.txt	// Windows UNIX
    /user/jim/myfile.txt		// UNIX

Полностью квалифицированный путь начинается с:

    /	UNIX
    \\	Windows
    X:\	Windows		одна буква после нее :
    SYS:\	Netware		имя тома может содержать несколько букв
    Macintosh HD:

Собственно для их нормализации нужна обработка . и .. которые могут встречаться
внутри:

    /user/jim/./myfile.txt		=>  /user/jim/myfile.txt
    /user/jim/../bob/myfile.txt 	=>  /user/bob/myfile.txt

То есть компонент . просто выкидываем
а для компонента .. выкидываем его и ближайший более верхний уровень
(при этом следим что бы не выкинуть самый верхний уровень).

2) Частично квалифицированные пути
   (Они опираются на текущую директорию)

    myfile.txt 		=>   {CURRENT_DIRECTORY}\myfile.txt
    mydir\myfile.txt	=>   {CURRENT_DIRECTORY}\mydir\myfile.txt
    .\myfile.txt		=>   {CURRENT_DIRECTORY}\myfile.txt
    ..\myfile.txt		=>   {CURRENT_DIRECTORY}\..\myfile.txt
    ./myfile.txt

    :mydir\myfile.txt	=>   {CURRENT_DIRECTORY}\mydir\myfile.txt  MacOS

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

    e:myfile.txt		=>   {CURRENT_DIRECTORY_FOR_DRIVE_E}\myfile.txt

Проблема в том - что не все системы держат текущую директорию для всех драйвов,
и ее можно получить для конкретного тома (например DOS).
Под Windows например получить текущую директорию для диска Х: можно так

    Сохраняем текущую директорию (SAVED)
    Меняем директорию на "X:"
    Берем текущую директорию - это ответ на наш вопрос
    Меняем текущую директорию на SAVED (востанавливаем старое состояние)

Эта операция опасная - так как не thread safe.

Собственно текущие каталоги на томах содержатся в environment variables, но в
удобоневаримом виде.

3) Пути опирающиеся на домашнюю директорию

В UNIX shell поддерживает имена директория вида
    ~   	домашняя директория текущего пользователя
    ~jim	домашняя директория пользователя jim

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

Имейти в виду ~ и ~jim - это директории, поэтому посли них в пути должен быть разделитель

    ~/myfile.txt		=> {ENVIRONMENT[HOME]}/myfile.txt
    ~jim/myfile.txt	        => {PASSWDFILE[jim, HOME_DIR_FIELD_INDEX]}\myfile.txt

А что делать если имя файла начинается с ~ и он лежит в текущей директории
(то есть первый символ relative path будет ~):

    ./~myfile.txt

  Операции с путями

  Определение типа пути

    есть 3 варианта
        абсолютный
        относительный  (относительно текущей директории)
        относительный относительно текущей директории конкретного тома

  Нормализация пути

    Нормализация пути - это преобразование пути к абсолютному пути
    (При этом удаляются все . , .. , лишнии / итд)

// 3rd party нестандартные расширения

// stdlib.h
char* _fullpath(char* buffer, const char* path, int buflen);

  Конвертация пути к native

    Конвертация пути к форме принятой на данной платформе
    Для cross-platform программ бывают ситуации когда нужно работать
    с именами файлов. Их вполне могут сохранить на одной платформе,
    а использовать на другой. Поэтому надо уметь их конвертировать.

    Это не всегда возможно в общем случае потому что на разных
    платформах символы которые могут присутсвовать в именах файлов
    разные
    пример:
        Disk:Utilities:Tcl/Tk
        валидное имя для MacOS, но совершенно невалидное в Windows и UNIX

    Как правило еще в всевожможных toolkits любят заводить переменные
    которые испульзуются для хранения текущего для данной платформы
        сепаратора имен		( / , \ , : )
        сепаратора путей        ( : , ; )

  Split Path

Собственно части на которые делиться path:

    Имя тома		(optional)
    Путь к директории       (volume related/current dir related) (optional)
    Базовое имя файла
    Расширение

Кроме того функции расщепления как правило занимаются и нормализацией тоже

// 3rd party нестандартные расширения

// stdlib.h
void _splitpath(const char* path, char* drive, char* dir, char* name, char* ext);
//				   X:		\DIR\       NAME	.EXT

// dir.h
int  fnsplit(const char* path, char* drive, char* dir, char* name, char* ext);

  Join path

Собственно обратная процедура для сборки path. Некоторые компоненты могут
отсутвовать - тогда беруться компоненты по умолчанию

// 3rd party нестандартные расширения

// stdlib.h
void _makepath(char* path, const char* drive, const char* dir,
           const char* name, const char* ext);

// dir.h
void fnmerge(char* path, const char* drive, const char* dir,
         const char* name, const char* ext);


81.3.4.2. ПОЛЕЗНЫЕ ОПЕРАЦИИ КОТОРЫЕ НЕ ПОДДЕРЖИВАЮТСЯ ФАЙЛОВЫМИ СИСТЕМАМИ НА ПРЯМУЮ

THIS SECTION IS UNDER CONSTRUCTION

    Удаление файла, даже если он Read/only

    Создание директории если часть компонентов пути не существует

    Рекурсивный обход директории
        помним про . и ..

    Удаление директории если она непустая
        естественно рекурсивно со всем ее содержимым.

    Подсчет места занимаемого директорией
        сумма размера файлов
        сумма занимаемых блоков

    Поиск файла в наборе paths в соответсвующей переменной окружений

// 3rd party RTL - не стандартные

// stdlib.h

char* searchpath(const char* file); 	// ищет в переменной PATH

void _searchenv(const char* file, const char* varname, char* buf)
                // ишет в указанной переменной
                // как правило это PATH, LIB, INCLUDE

    Проверка существования объекта файловой системы

    Обычно берут функцию взятия аттрибутов по имени
    (stat() или GetFileAttributes())
    если она возвращает ошибку что файла нет то его нет

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

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

Собственно в UNIX для этого в stat.h есть макросы
    S_ISBLK(mode)
    S_ISCHR(mode)
    S_ISDIR(mode)
    S_ISFIFO(mode)
    S_ISREG(mode)	regular file
    S_ISLNK(mode)	symbolic link
    S_ISSOCK(mode)  socket

А так для переносимого кода пишут свои функции типа:

    is_file(filename)
    is_dir(filename)
    is_symlink(filename)

    Проверка возможности доступа определенного типа
    к файлу (access)

Под UNIX существует стандартный интерфейс для этого
(он смотрит UNIX file permissions и UID, GID).

// unistd.h

int access(const char* path, int amode);
    // amode is:
    //	R_OK	- check for read access
    //	W_OK	- check for write access
    //	X_OK	- check for execute access
    //	F_OK	- check for exist

// Linux

int euidaccess(const char* path, int amode);

Для Windows такого интерфейса нет поэтому обычно делают
урезанную имплементацию - которая проверяет exist (см выше),
а так же проверяет Read Only аттрибут (а security descriptors
не проверяет, это уже делает система при открытии).

Часто делают обкладки для совсем простых интерфейсов

    is_writeable(filename)
    is_readable(filename)
    is_executable(filename)

потому что так удобнее пользоваться.

    Копирование файла
    (не всегда есть системная функция)

    Обычное
    Replace

    Сравнение данных двух файлов
    (Вначале можно сравнить длинны - если они не совпадают
     то файлы точно различные)

    Сравнение данных двух директорий
    (как правило сравниваются не данные файлов,
     а метаданные (длинна, времена доступа итд)

    Поиск данных в файле

    Как правило используются
        текстовый шаблон
        бинарный шаблон
    реже регулярные выражения


81.3.4.3. СТАНДАРТНЫЕ БИБЛИОТЕКИ ДЛЯ РАБОТЫ С ФАЙЛАМИ

THIS SECTION IS UNDER CONSTRUCTION

    Часто приходится работать с файлом мальнькими кусочками, постоянно делать вызовы
API операционных систем очень неэффективно, поэтому используется буферизация

  С stdio.h

FILE * fopen(const char * filename, const char * mode);
    // синтаксис для mode
    //	(r|w|a)[+][b]
    // "r"
    // "w"
    // "a"
    // "r+"
    // "w+"
    // "a+"

FILE *	freopen(const char * filename, char * mode, FILE * stream);

int	fclose(FILE * stream);
FILE *	fdopen(int handle, char * mode);
int	fileno(FILE * stream);		// нужен что бы сделать stat например

FILE *	tmpfile(void);

int	feof(FILE * stream);

int	fflush(FILE * stream);

int	ferror(FILE * stream);
void	clearerr(FILE * stream);

int	fgetpos(FILE * stream, fpos_t pos);
int	fsetpos(FILE * stream, const fpos_t * pos);
int	fseek(FILE * stream, long offset, int whence);
long	ftell(FILE * stream);
void	rewind(FILE * stream);

int	fgetc(FILE * stream);
char *	fgets(char * buf, int n, FILE * stream);

int	ungetc(int c, FILE * stream);

int	fputc(int c, FILE * stream);
int	fputs(const char * s, FILE * stream);

size_t	fread(void * ptr,
          size_t size,
          size_t n,
          FILE * stream);

size_t	fwrite(const void * ptr,
           size_t size,
           size_t n,
           FILE * stream);

int	fprintf(FILE * stream, const char * format, ...);
int	fscanf(FILE * stream, const char * format, ...);
int 	vfprintf(FILE *, const char *, va_list);

int	setvbuf(FILE * stream,
            char * buf,
            int    type,
            size_t size);
    // type is:
    //	_IONBF	- no buffering
    //	_IOLBF	- line buffering
    //	_IOFBF	- block buffering

void	setbuf(FILE * stream, char * buf);	// must be >= BUFSIZ

FILE * 	stdin;		// standart input stream
FILE *	stdout;		// standart output stream
FILE *  stderr;		// standart error stream

int 	fcloseall(void);	//
int 	flushall(void);		// редко но встречается

void 	flockfile(FILE*);
void	funlockfile(FILE*);
int	ftrylockfile(FILE*);

Соответственно есть и wide аналоги функций:

wint_t   fgetwc(FILE *);
wint_t   fputwc(wint_t, FILE *);
wint_t   ungetwc(wint_t, FILE *);
wchar_t* fgetws(wchar_t *, int, FILE *);
int 	 fputws(const wchar_t *, FILE *);

int 	 fwprintf(FILE *, const wchar_t *, ...);
int 	 vfwprintf(FILE *, const wchar_t *, va_list);
int 	 fwscanf(FILE *, const wchar_t *, ...);

Ввод/вывод с консоли (putchar, printf, getc, итд) мы здесь не рассматриваем.
Наша цель - это файлы.

// stdio.h
//	семейство unlocked функций - они быстрее но не thread-safe
//	некоторые POSIX.1, остальные нестандартные варианты

int 	getc_unlocked(FILE *stream);
int 	getchar_unlocked(void);
int 	putc_unlocked(int c, FILE *stream);
int 	putchar_unlocked(int c);

void 	clearerr_unlocked(FILE *stream);
int 	feof_unlocked(FILE *stream);
int 	ferror_unlocked(FILE *stream);
int 	fileno_unlocked(FILE *stream);
int 	fflush_unlocked(FILE *stream);
int 	fgetc_unlocked(FILE *stream);
int 	fputc_unlocked(int c, FILE *stream);
size_t  fread_unlocked(void *ptr, size_t size, size_t n, FILE *stream);
size_t  fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *stream);

char*	fgets_unlocked(char *s, int n, FILE *stream);
int 	fputs_unlocked(const char *s, FILE *stream);

wint_t 	getwc_unlocked(FILE *stream);
wint_t 	getwchar_unlocked(void);
wint_t 	fgetwc_unlocked(FILE *stream);
wint_t 	fputwc_unlocked(wchar_t wc, FILE *stream);
wint_t 	putwc_unlocked(wchar_t wc, FILE *stream);
wint_t 	putwchar_unlocked(wchar_t wc);
wchar_t* fgetws_unlocked(wchar_t *ws, int n, FILE *stream);
int 	fputws_unlocked(const wchar_t *ws, FILE *stream);

  Взаимодействие C standart library c платформой

На платформах свои типы файловых дескрипторов. Стандартные C RTL функции работы с
памятью напрямую маппируются в системные вызовы только под UNIX.

Поэтому тот handle который возвращает например функция open() не является системным
handle файла, и его нельзя использовать в системных функциях.

// io.h

HANDLE _get_osfhandle(int filedes);

Так же но реже имплементируют функцию которая позволяет создать объект handle файла
RTL по handle файла открытого системными функциями

// io.h

int  _open_osfhandle(HANDLE osfhandle, int flags);


81.3.4.4. ТИПОВЫЕ КЛАССЫ ДЛЯ РАБОТЫ С ФАЙЛОВОЙ СИСТЕМОЙ

  Qt

class QDir
{
public:
    QDir(const QDir& dir);
    QDir(const QString& path = QString());
    QDir(const QString& path, const QString& nameFilter,
         SortFlags sort = SortFlags( Name | IgnoreCase ), Filters filters = AllEntries);
    ~QDir ();
    QString absoluteFilePath(const QString& fileName) const;
    QString absolutePath() const;
    QString canonicalPath() const;
    bool    cd(const QString& dirName);
    bool    cdUp();
    uint    count() const;
    QString dirName() const;
    QFileInfoList entryInfoList(const QStringList& nameFilters,
                    Filters filters = NoFilter,
                    SortFlags sort = NoSort) const;
    QFileInfoList entryInfoList(Filters filters = NoFilter, SortFlags sort = NoSort) const;
    QStringList   entryList(const QStringList& nameFilters, Filters filters = NoFilter,
                SortFlags sort = NoSort) const;
    QStringList   entryList(Filters filters = NoFilter, SortFlags sort = NoSort) const;
    bool exists(const QString& name) const;
    bool exists() const;
    QString filePath(const QString & fileName) const;
    Filters filter() const;
    bool isAbsolute() const;
    bool isReadable() const;
    bool isRelative() const;
    bool isRoot() const;
    bool makeAbsolute();
    bool mkdir(const QString& dirName) const;
    bool mkpath(const QString& dirPath) const;
    QStringList nameFilters() const;
    QString     path() const;
    void        refresh () const;
    QString relativeFilePath(const QString& fileName) const;
    bool remove(const QString& fileName);
    bool rename(const QString& oldName, const QString& newName);
    bool rmdir(const QString& dirName) const;
    bool rmpath(const QString& dirPath) const;
    void setFilter(Filters filters);
    void setNameFilters( const QStringList& nameFilters);
    void setPath(const QString& path);
    void setSorting(SortFlags sort);
    SortFlags sorting() const;
    bool operator != (const QDir& dir) const;
    QDir& operator = (const QDir& dir);
    bool operator == (const QDir& dir) const;
    QString operator[] (int pos) const;

static	void addResourceSearchPath(const QString& path);
static	QString cleanPath(const QString& path);
static	QDir current();
static	QString currentPath();
static	QFileInfoList drives();
static	QString fromNativeSeparators(const QString& pathName);
static	QDir home();
static	QString homePath();
static	bool isAbsolutePath(const QString& path);
static	bool isRelativePath(const QString& path);
static	bool match(const QString& filter, const QString& fileName);
static	bool match(const QStringList& filters, const QString& fileName);
static	QDir root();
static	QString rootPath();
static	QChar separator();
static	bool setCurrent(const QString& path);
static	QDir temp();
static	QString tempPath();
static	QString toNativeSeparators(const QString& pathName);
};

class QFile : QIODevice
{
public:
    QFile ( const QString & name )
    QFile ( QObject * parent )
    QFile ( const QString & name, QObject * parent )
    ~QFile ()
virtual bool atEnd () const
    bool copy ( const QString & newName )
    FileError error () const
    bool exists () const
    QString fileName () const
    bool flush ()
    int handle () const
virtual bool isSequential () const
    bool link ( const QString & linkName )
virtual bool open ( OpenMode mode )
    bool open ( FILE * fh, OpenMode mode )
    bool open ( int fd, OpenMode mode )
    Permissions permissions () const
    bool remove ()
    bool rename ( const QString & newName )
    bool resize ( qint64 sz )
    void setFileName ( const QString & name )
    bool setPermissions ( Permissions permissions )
virtual qint64 size () const
    QString symLinkTarget () const
    void unsetError ()

static  bool copy ( const QString & fileName, const QString & newName )
static	QString decodeName ( const QByteArray & localFileName )
static	QString decodeName ( const char * localFileName )
static	QByteArray encodeName ( const QString & fileName )
static	bool exists ( const QString & fileName )
static	bool link ( const QString & fileName, const QString & linkName )
static	Permissions permissions ( const QString & fileName )
static	bool remove ( const QString & fileName )
static	bool rename ( const QString & oldName, const QString & newName )
static	bool resize ( const QString & fileName, qint64 sz )
static	void setDecodingFunction ( DecoderFn function )
static	void setEncodingFunction ( EncoderFn function )
static	bool setPermissions ( const QString & fileName, Permissions permissions )
static	QString symLinkTarget ( const QString & fileName )
};

class QIODevice : public QObject
{
public:
    QIODevice ()
    QIODevice ( QObject * parent )
virtual ~QIODevice ()
virtual bool atEnd () const
virtual qint64 bytesAvailable () const
virtual qint64 bytesToWrite () const
virtual bool canReadLine () const
virtual void close ()
    QString errorString () const
    bool getChar ( char * c )
    bool isOpen () const
    bool isReadable () const
virtual bool isSequential () const
    bool isTextModeEnabled () const
    bool isWritable () const
virtual bool open ( OpenMode mode )
    OpenMode openMode () const
    qint64 peek ( char * data, qint64 maxSize )
    QByteArray peek ( qint64 maxSize )
virtual qint64 pos () const
    bool putChar ( char c )
    qint64 read ( char * data, qint64 maxSize )
    QByteArray read ( qint64 maxSize )
    QByteArray readAll ()
    qint64 readLine ( char * data, qint64 maxSize )
    QByteArray readLine ( qint64 maxSize = 0 )
virtual bool reset ()
virtual bool seek ( qint64 pos )
    void setTextModeEnabled ( bool enabled )
virtual qint64 size () const
    void ungetChar ( char c )
virtual bool waitForBytesWritten ( int msecs )
virtual bool waitForReadyRead ( int msecs )
    qint64 write ( const char * data, qint64 maxSize )
    qint64 write ( const QByteArray & byteArray )

protected:

virtual qint64 readData ( char * data, qint64 maxSize ) = 0
virtual qint64 readLineData ( char * data, qint64 maxSize )
    void setErrorString ( const QString & str )
    void setOpenMode ( OpenMode openMode )
virtual qint64 writeData ( const char * data, qint64 maxSize ) = 0
};

class QFileInfo
{
    QFileInfo ()
    QFileInfo ( const QString & file )
    QFileInfo ( const QFile & file )
    QFileInfo ( const QDir & dir, const QString & file )
    QFileInfo ( const QFileInfo & fileinfo )
    ~QFileInfo ()
    QDir absoluteDir () const
    QString absoluteFilePath () const
    QString absolutePath () const
    QString baseName () const
    bool caching () const
    QString canonicalFilePath () const
    QString canonicalPath () const
    QString completeBaseName () const
    QString completeSuffix () const
    QDateTime created () const
    QDir dir () const
    bool exists () const
    QString fileName () const
    QString	filePath () const
    QString group () const
    uint groupId () const
    bool isAbsolute () const
    bool isDir () const
    bool isExecutable () const
    bool isFile () const
    bool isHidden () const
    bool isReadable () const
    bool isRelative () const
    bool isRoot () const
    bool isSymLink () const
    bool isWritable () const
    QDateTime lastModified () const
    QDateTime lastRead () const
    bool makeAbsolute ()
    QString owner () const
    uint ownerId () const
    QString path () const
    bool permission ( QFile::Permissions permissions ) const
    QFile::Permissions permissions () const
    void refresh ()
    void setCaching ( bool enable )
    void setFile ( const QString & file )
    void setFile ( const QFile & file )
    void setFile ( const QDir & dir, const QString & file )
    qint64 size () const
    QString suffix () const
    QString symLinkTarget () const
    bool operator!= ( const QFileInfo & fileinfo )
    bool operator!= ( const QFileInfo & fileinfo ) const
    QFileInfo & operator= ( const QFileInfo & fileinfo )
    bool operator== ( const QFileInfo & fileinfo )
    bool operator== ( const QFileInfo & fileinfo ) const
}

  MFC

class CFile : public CObject
{
    DECLARE_DYNAMIC(CFile)

public:
    enum OpenFlags {
        modeRead =          0x0000,
        modeWrite =         0x0001,
        modeReadWrite =     0x0002,
        shareCompat =       0x0000,
        shareExclusive =    0x0010,
        shareDenyWrite =    0x0020,
        shareDenyRead =     0x0030,
        shareDenyNone =     0x0040,
        modeNoInherit =     0x0080,
        modeCreate =        0x1000,
        modeNoTruncate =    0x2000,
        typeText =          0x4000, // typeText and typeBinary are used in
        typeBinary =   (int)0x8000 // derived classes only
        };

    enum Attribute {
        normal =    0x00,
        readOnly =  0x01,
        hidden =    0x02,
        system =    0x04,
        volume =    0x08,
        directory = 0x10,
        archive =   0x20
        };

    enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 };

    enum { hFileNull = -1 };

    CFile();
    CFile(int hFile);
    CFile(LPCTSTR lpszFileName, UINT nOpenFlags);

    UINT m_hFile;
    operator HFILE() const;

    virtual DWORD GetPosition() const;
    BOOL GetStatus(CFileStatus& rStatus) const;
    virtual CString GetFileName() const;
    virtual CString GetFileTitle() const;
    virtual CString GetFilePath() const;
    virtual void SetFilePath(LPCTSTR lpszNewName);

    virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags,
        CFileException* pError = NULL);

    static void PASCAL Rename(LPCTSTR lpszOldName,
                LPCTSTR lpszNewName);
    static void PASCAL Remove(LPCTSTR lpszFileName);
    static BOOL PASCAL GetStatus(LPCTSTR lpszFileName,
                CFileStatus& rStatus);
    static void PASCAL SetStatus(LPCTSTR lpszFileName,
                const CFileStatus& status);

    DWORD SeekToEnd();
    void SeekToBegin();

    // backward compatible ReadHuge and WriteHuge
    DWORD ReadHuge(void* lpBuffer, DWORD dwCount);
    void WriteHuge(const void* lpBuffer, DWORD dwCount);

    virtual CFile* Duplicate() const;

    virtual LONG Seek(LONG lOff, UINT nFrom);
    virtual void SetLength(DWORD dwNewLen);
    virtual DWORD GetLength() const;

    virtual UINT Read(void* lpBuf, UINT nCount);
    virtual void Write(const void* lpBuf, UINT nCount);

    virtual void LockRange(DWORD dwPos, DWORD dwCount);
    virtual void UnlockRange(DWORD dwPos, DWORD dwCount);

    virtual void Abort();
    virtual void Flush();
    virtual void Close();

public:
    virtual ~CFile();
    enum BufferCommand { bufferRead, bufferWrite, bufferCommit, bufferCheck };
    virtual UINT GetBufferPtr(UINT nCommand, UINT nCount = 0,
        void** ppBufStart = NULL, void** ppBufMax = NULL);

protected:
    BOOL m_bCloseOnDelete;
    CString m_strFileName;
};

class CStdioFile : public CFile
{
    DECLARE_DYNAMIC(CStdioFile)

public:
    CStdioFile();
    CStdioFile(FILE* pOpenStream);
    CStdioFile(LPCTSTR lpszFileName, UINT nOpenFlags);

    FILE* m_pStream;    // stdio FILE
                // m_hFile from base class is _fileno(m_pStream)

    virtual void WriteString(LPCTSTR lpsz);
    virtual LPTSTR ReadString(LPTSTR lpsz, UINT nMax);
    virtual BOOL ReadString(CString& rString);

public:
    virtual ~CStdioFile();
    virtual DWORD GetPosition() const;
    virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags,
        CFileException* pError = NULL);
    virtual UINT Read(void* lpBuf, UINT nCount);
    virtual void Write(const void* lpBuf, UINT nCount);
    virtual LONG Seek(LONG lOff, UINT nFrom);
    virtual void Abort();
    virtual void Flush();
    virtual void Close();

    // Unsupported APIs
    virtual CFile* Duplicate() const;
    virtual void LockRange(DWORD dwPos, DWORD dwCount);
    virtual void UnlockRange(DWORD dwPos, DWORD dwCount);
};

class CFileFind : public CObject
{
public:
    CFileFind();
    virtual ~CFileFind();

public:
    DWORD GetLength() const;
#if defined(_X86_) || defined(_ALPHA_)
    __int64 GetLength64() const;
#endif
    virtual CString GetFileName() const;
    virtual CString GetFilePath() const;
    virtual CString GetFileTitle() const;
    virtual CString GetFileURL() const;
    virtual CString GetRoot() const;

    virtual BOOL GetLastWriteTime(FILETIME* pTimeStamp) const;
    virtual BOOL GetLastAccessTime(FILETIME* pTimeStamp) const;
    virtual BOOL GetCreationTime(FILETIME* pTimeStamp) const;
    virtual BOOL GetLastWriteTime(CTime& refTime) const;
    virtual BOOL GetLastAccessTime(CTime& refTime) const;
    virtual BOOL GetCreationTime(CTime& refTime) const;

    virtual BOOL MatchesMask(DWORD dwMask) const;

    virtual BOOL IsDots() const;
    // these aren't virtual because they all use MatchesMask(), which is
    BOOL IsReadOnly() const;
    BOOL IsDirectory() const;
    BOOL IsCompressed() const;
    BOOL IsSystem() const;
    BOOL IsHidden() const;
    BOOL IsTemporary() const;
    BOOL IsNormal() const;
    BOOL IsArchived() const;

    void Close();
    virtual BOOL FindFile(LPCTSTR pstrName = NULL, DWORD dwUnused = 0);
    virtual BOOL FindNextFile();

protected:
    virtual void CloseContext();

protected:
    void* m_pFoundInfo;
    void* m_pNextInfo;
    HANDLE m_hContext;
    BOOL m_bGotLast;
    CString m_strRoot;
    TCHAR m_chDirSeparator;     // not '\\' for Internet classes
    DECLARE_DYNAMIC(CFileFind)
};


81.3.5. ВОПРОСЫ ENTERPRISE STORAGE

THIS SECTION IS UNDER CONSTRUCTION

  Backup

    отличие от архивации:
        backup осуществляется виртуально в один и тот же момент
        времени для всего backup set. Если система работает то для
        этого используются механизмы snapshoting (hot processing).

    типы backup:
        Full		(полностью backup set)
        Differential	(дельта от полного backup set)
        Incremental	(дальта от другого backup set)

        CDP (Continious Data Protection)
            все изменения идут как мельчайшие инкременты,
            состояние можно вернуть на любой момент времени

    типы backup:
        Sector-level
        File-level

        Mixed (synthetic) backups
            например файловый инкремент к посекторному backup

  Restore

    обычный restore
        всего backup set
        части backup set

    Disaster Recovery (DR)
        востанавливаем всю систему
        (при этом надо востанавливать таблицы партиций,
         операционную систему итд).

    Миграция:
        P2P
        P2V
        V2P
            собственно набор процедур по установке дополнительных
            драйверов и привязки к оборудованию.

  Иерархия storage

Стадартный принцип - все что долго не используется врядли понадобиться скоро

HSM (Hierarchical Storage Management).
    Заменяем файлы в файловой системы на ссылки на них во внешнем хранилище
    При обращение к файлам вытягиваем их из внешнего хранилища

Storage Tiering
    Разные данные имеют разную полезность, поэтому можно сделать политики
    которые будут их хранить по разному.

    Например бугалтерский отчет на RAID-5 в течении 3 лет,
    потом на ленту итд.

  Deduplication

Времена когда в компаниях был один большой сервер, где хранили все и регулярно
его backupили на ленту - ушли в прошлое. Большие диски привели к тому что у всех
все лежит локально (или по крайней мере копии локально).
Соответветсвенно возникают проблемы с размерами клиентских backup.
Например: 100 машин, на каждой Windows и Office. Очень много лишней информации.

Deduplication
    source-based deduplication
        осуществляется на источнике
        static
               жестко забитый content (например системные файлы)
        dynamic
           самообучаемая
             очень удобно для инкрементов

    target-based deduplication
            осуществляется в хранилище
        static
        dynamic
    [в отличии от source-based может полностью проверять данные]

    Дедупликация
        File level
            отдельные файлы
        Block level
            блоки файлов и/или диска (фиксированного размера)
        Sector level
            блоки диска (на самом деле как правило исползуют
            кластеры или группы кластеров).

  Объектно-ориентированный storage

        Block-based	Object-based
аллокация       внешняя		внутренняя
адрессация	[block,len]	[object, byte range]
операции	Read Block 	Create Object
        Write Block	Delete Object
                Read Object
                Write Object

Есть даже SCSI команды для поддержки object-oriented storage.


81.4. СЕТЕВАЯ ПОДСИСТЕМА

THIS SECTION IS UNDER CONSTRUCTION

Много различных типов низкоуровневых сетевых сред
    Ethernet
    Token Ring
    SLIP
    PPP
    PPPoE
    FDDI
    ATM
    Bluetooth
    WiFi

Много различных типов протоколов
    IPv4
    IPv6
    NetBEUI
    IPX
    AppleTalk
Все надо поддерживать

Сетевое взаимодействие
Конфигурирование интерфейсов
Конфигурирование рутинга
Фильтрация

Сетевые интерфейсы (режимы работы и флаги)
UNIX style:
    IFF_UP
    IFF_BROADCAST
    IFF_LOOPBACK
    IFF_POINTTOPOINT
    IFF_NOARP
    IFF_PROMISC
    IFF_MULTICAST
    IFF_ALLMULTI

Назначение пакета
    This Host
    Broadcast
    Multicast
    Other host
    Outgoing
    Loopback

Scatter/Gather буфера
    Данные
    Заголовки

соединения
     o  Connection-oriented
    o  Connection-less


81.4.1. ОБЩАЯ АРХИТЕКТУРА СЕТЕВОЙ ПОДСИСТЕМЫ

THIS SECTION IS UNDER CONSTRUCTION

Общая схема


81.4.1.0. СЕТЕВАЯ КАРТА ETHERNET

THIS SECTION IS UNDER CONSTRUCTION

    Адресса
        Индивидуальные		Unicast
        Групповые		Multicast
        Широковещательный       Broadcast

Режимы работы сетевой карты:
    Прием (независимо)
        Unicast (только свой)
        Broadcast
        Limited Multicast
        All Multicast
        Promiscous mode (all packets)

Packet Rings

Типовые запросы к сетевой карте

    Установить режим работы
        Кроме режимов приема еще и включить/выключить adapter

    Отослать пакет (поставить в очередь на отсылку)

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

    Получить Статистику
        Количество принятых/отосланных пакетов
        Статистика об ошибках
            Как правило еще и разбита по типу ошибок

    Получить MAC адресс сетевой карты

    Установить MAC адресс сетевой карты
        на самом деле fake, так как карта отправит frame который в буфере
        с тем MAC адрессом который там указан

    Добавить Multicast address в список приема

    Удалить  Multicast address в список приема

Limited Multicast
    Не хочется принимать все multicast пакеты ради нескольких групп
    Поэтому современные карты имеют порядка 10-16 регистров которые содержат
    маски и адресса для limited multicast
    Multicast пакет принимается когда:
        INCOMING_PACKET_TARGET_MAC AND MASK = ADDRESS
    Но если требуется принимать более 10-16 multicast адрессов, то тогда
    выбирается наиболее близкая пара адресс/маска и модифицируется чтобы
    принимать еще и другую группу.
    В результате будут приниматься пакеты и из тех групп из которых не недо,
    поэтому драйвер должен отфильтровывать такие случаи.

Типовые регистры сетевой карты

Ошибки приема Ethernet
    Long	> 1518, CRC ok
    Runt	< 64, CRC ok
    Jabber	> 1528, CRC wrong
    Alignment - нет выравнивания побайтового
    CRC	правильная длинна, CRC wrong

Ошибки отсылки Ethernet
    Не смогла за 10 оправить frame из-за коллизий


81.4.2. ИНТЕРФЕЙСЫ ДРАЙВЕРОВ ФИЗИЧЕСКИХ УСТРОЙСТВ

THIS SECTION IS UNDER CONSTRUCTION

Концептульный API для драйверов физических сетевых устройств
    net_device Linux
        init
        uninit
        open
        stop
        hard_start_xmit
        hard_header
        rebuild_header
        set_multicast_list
        set_mac_address
        do_ioctl
        set_config	прерывания итд
        hard_header_cache
        header_cache_update
        change_mtu
        tx_timeout
        hard_header_parse
        neigh_setup
        get_stats
        get_wireless_stats

    NDIS miniport Windows
        MiniportSetOptions
        MiniportInitializeEx
        MiniportHaltEx
        MiniportDriverUnload
        MiniportPause
        MiniportRestart
        MiniportOldRequest
        MiniportCheckForHangEx
        MiniportResetEx
        MiniportDevicePnPEventNotify
        MiniportShutdownEx

Типовые properties

    OID_GEN_MEDIA_SUPPORTED
    OID_GEN_MEDIA_IN_USE
    OID_GEN_MAXIMUM_FRAME_SIZE
    OID_GEN_LINK_SPEED
    OID_GEN_TRANSMIT_BUFFER_SPACE
    OID_GEN_RECEIVE_BUFFER_SPACE
    OID_GEN_TRANSMIT_BLOCK_SIZE
    OID_GEN_RECEIVE_BLOCK_SIZE
    OID_GEN_MAC_OPTIONS
    OID_GEN_MAC_ADDRESS

    OID_GEN_PROMISCUOUS_MODE
    OID_GEN_XMIT_LINK_SPEED
    OID_GEN_RCV_LINK_SPEED
    OID_GEN_MEDIA_CONNECT_STATUS_EX

для Ethernet:
    OID_802_3_PERMANENT_ADDRESS
    OID_802_3_CURRENT_ADDRESS
    OID_802_3_MULTICAST_LIST
    OID_802_3_MAXIMUM_LIST_SIZE

    дальше в основном статистика


81.4.3. СЕТЕВЫЕ ОКРУЖЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

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

Задача на прием:
    Вытащить содержимое данных из нижнеуровневого frame
        как правило это не копирование, а просто установка указателей и длинны
    Определить длинну frame
    Определить протокол которому назначается пакет
    Передать данные драйверу протокола

Задача на передачу:
    Сформировать нижнеуровневый frame
        но для этого надо знать target MAC адресс
        (Разрешение link local MAC address идет как правило на уровень выше).
    Передать cформированный frame драйверу сетевой карты

На примере Ethernet:

802.2 Frame:

802.3 Frame:

Ethernet II frame:

Ethernet SNAP frame:


81.4.3.1. БЫСТРЫЙ FORWARDING НА УРОВНЕ NETWORK ENVIRONMENT

THIS SECTION IS UNDER CONSTRUCTION

MPLS


81.4.4. INTERMEDIATE DRIVERS

THIS SECTION IS UNDER CONSTRUCTION

  Нижние Firewalls

  Sniffers


81.4.5. ИНТЕРФЕЙСЫ ДРАЙВЕРОВ СЕТЕВЫХ ПРОТОКОЛОВ

THIS SECTION IS UNDER CONSTRUCTION

Что вообще должны делать драйверы сетевых протоколов?

  Типы Endpoints

У нас есть 3 типа endpoints у соединений:

    Datagram
    Sequential Datagram
    Stream

 ----------------------------------------
Тип		Гарантированная	Упорядоченность
        доставка	данных
 ----------------------------------------
Datagram	нет		нет
Sequential Dg	да		да
Stream		да		да
 ----------------------------------------

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

C одной стороны нижележащие сетевые уровни бомбардируют драйвер сетевого протокола
пакетами которые пришли по сети и предназначены для данного протокола.
С другой стороны прикладные программы делают свои запросы.

Рассмотрим приход сетевого пакета на примере некоторого общего драйвера протокола IPv4.

    1) Проверяем размер данных которые передали нам с нижнего уровня
       Если он меньше 20 байт  (IP пакет не может быть меньше 20 байт)
       то мы его выбрасываем
    2) Проверяем версию в заголовке
           Если она не 4  (IPv4) то выбрасываем пакет
    3) Проверяем длинну заголовка
           Если она меньше 5 (т.е. меньше 20 байт) то выбрасываем пакет
    4) Проверяем соответсвует (не больше ли) длинна пакета длинны переданной
           с более нижнего уровня.
           Если не соответсвует то выбрасываем пакет

    TODO: Расписать

  Реассемблинг

Кроме того при приеме если надо выполняется сборка датаграммы из фрагментов.
Каждый фрагмент который пришел откладывается во временный буфер, где он некоторое
строго определенное время ждет придут ли все фрагменты. Если за это время ВСЕ
фрагменты не придут, то пришедшие фрагменты сбрасываются.

  Состояния Endpoints

TODO:

  Доставка datagrams

Если для пришедшей datagram есть endpoint, datagram ставиться в список принятых
пакетов для данного endpoint. И соответсвенно приложения которые принимают датаграммы
с этого endpoint могут ее получить.

Если же endpointа нет, то ее получит тот кто подписан на соответсующий raw endpoint,
если же никого нет то отошлют сообщение о том что датаграмма не может быть
доставлена.

  Доставка Sequential datagram

  Доставка Stream

Детальное описание
    IPv4
    IPv6
    IPX

Концептуальный API для драйверов сетевых протоколов

Windows
    NDIS Protocol
        ProtocolSetOptions
        ProtocolBindAdapterEx
        ProtocolUnbindAdapterEx
        ProtocolOpenAdapterCompleteEx
        ProtocolCloseAdapterCompleteEx
        ProtocolNetPnPEvent
        ProtocolUninstall
    IOCTL_TDI_ACCEPT
    IOCTL_TDI_CONNECT
    IOCTL_TDI_DISCONNECT
    IOCTL_TDI_LISTEN
    IOCTL_TDI_QUERY_INFORMATION
    IOCTL_TDI_RECEIVE
    IOCTL_TDI_RECEIVE_DATAGRAM
    IOCTL_TDI_SEND
    IOCTL_TDI_SEND_DATAGRAM
    IOCTL_TDI_SET_EVENT_HANDLER
    IOCTL_TDI_SET_INFORMATION
    IOCTL_TDI_ASSOCIATE_ADDRESS
    IOCTL_TDI_DISASSOCIATE_ADDRESS

    TDI_CONNECTION_INFORMATION

а для управления всем остальным используются IOCTLs

    IOCTL_IP_SET_ADDRESS
    IOCTL_IP_SET_DHCP_INTERFACE
        IOCTL_IP_SET_MAP_ROUTE_POINTER
    IOCTL_IP_GET_PNP_ARP_POINTERS
    IOCTL_IP_ADD_NTE
    IOCTL_IP_DELETE_NTE
    IOCTL_IP_GET_NTE_INFO

    IOCTL_IPV6_QUERY_INTERFACE
    IOCTL_IPV6_QUERY_ADDRESS
    IOCTL_IPV6_QUERY_NEIGHBOR_CACHE
    IOCTL_IPV6_QUERY_ROUTE_CACHE
    IOCTL_IPV6_QUERY_PREFIX_LIST
    IOCTL_IPV6_QUERY_ROUTER_LIST
    IOCTL_IPV6_ADD_MEMBERSHIP
    IOCTL_IPV6_DROP_MEMBERSHIP
    IOCTL_IPV6_QUERY_ROUTE_TABLE
    IOCTL_IPV6_UPDATE_ROUTE_TABLE
    IOCTL_IPV6_UPDATE_ADDRESS
    IOCTL_IPV6_FLUSH_NEIGHBOR_CACHE
    IOCTL_IPV6_FLUSH_ROUTE_CACHE


81.4.5.1. ТРАНКИНГ

THIS SECTION IS UNDER CONSTRUCTION

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


81.4.6. РАЗРЕШЕНИЕ ЛОКАЛЬНЫХ АДРЕССОВ

THIS SECTION IS UNDER CONSTRUCTION

Посмотрите секцию 84.1.1. РАЗРЕШЕНИЕ ЛОКАЛЬНЫХ АДРЕССОВ


81.4.7. ROUTING

THIS SECTION IS UNDER CONSTRUCTION

Прочтите секцию 55.9.3.4. МАРШРУТИЗАЦИЯ


81.4.8. FILTER DRIVERS

THIS SECTION IS UNDER CONSTRUCTION

Верхнеуровневые фильтры сидящие выше драйвера протокола.


81.4.9. QoS

THIS SECTION IS UNDER CONSTRUCTION

QoS (Quality of Services)

             QoS
        /   \
      IntServ  DiffServ

IntServ (Integrated Services)
    для конечных пользователей

DiffServ (Differential Services)
    для классов траффика

Резервирование пропускной способности.


81.4.10. NAT

THIS SECTION IS UNDER CONSTRUCTION

  NAT

1:

2:

3:

4,5:

  DMZ


81.4.11. ТУНЕЛИРОВАНИЕ И VPN

THIS SECTION IS UNDER CONSTRUCTION

  Tunneling

  VPN


81.4.11.1. MOBILITY

THIS SECTION IS UNDER CONSTRUCTION


81.4.12. SOCKET PROVIDER

THIS SECTION IS UNDER CONSTRUCTION

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


81.4.12.1. СТРУКТУРЫ ПРОТОКОЛЬНЫХ АДРЕСОВ ДЛЯ ИНТЕРФЕЙСА СОКЕТОВ

THIS SECTION IS UNDER CONSTRUCTION

struct sockaddr_in
{
    short int	sin_family;
    unsigned short int sin_port;
    struct in_addr   sin_addr;
};

struct sockaddr_in6
{
    short int	sin6_family;
    unsigned short int sin6_port;
    unsigned int sin6_flowinfo;
    struct in6_aadr sin6_addr;
    unsigned int sin6_scope_id;
};


81.4.13. РАЗРЕШЕНИЕ ИМЕН

THIS SECTION IS UNDER CONSTRUCTION

В первую очередь это DNS

  Преобразование имени в адресс и обратно

  Получение имени текущего хоста

int	gethostname(char * name,    	// Buffer for name
            int    namelen);    // Buffer length
    Place name of local host to buffer.
    if ok return 0
    if fail return SOCKET_ERROR (-1)

  Получение адресса хоста по имени

// IPv4
struct hostent *  gethostbyname(char * name);	// Name of Host
    // Retrive information about host by it's name
    // if ok return structure for host
    // if fail return NULL
    // hostent is one-per-thread static buffer
    // DO NOT MODIFY THIS hostent

    struct hostent
    {
        char  * 	h_name;		// Host name
        char  **	h_aliases;	// Alternative host names
        short		h_addrtype;	// Address Type
        short		h_length;	// Address Length
        char  **	h_addr_list;	// List of addresses
    };

struct	hostent * gethostbyname2(const char * hostname, // Name of host
                 int   family);		// AF_INET or AF_INET6

    Get host by name with additional protocol family parameter.
    Seee gethostbyname() for more info.

struct hostent * gethostbyname_r(const char *,
                 struct hostent *,
                 char *,
                 int,
                 int *h_errnop);

// netdb.h

int getaddrinfo(const char* hostname,
        const char* servicename,
        const struct addrinfo* hints,
        struct addrinfo** res);

struct addrinfo
{
    int	ai_flags;
            AI_ADDRCONFIG
            AI_CANNONNAME
            AI_NUMERICHOST
            AI_PASSIVE
    int	ai_family;
    int	ai_socktype;
    int	ai_protocol;
    socklen_t ai_addrlen;
    struct sockaddr_t* ai_addr;
    char*  ai_cannonname;
    struct addrinfo* next;
}

return
    0
    EAI_EAGAIN
    EAI_BADFLAGS
    EAI_FAIL
    EAI_FAMILY
    EAI_MEMORY
    EAI_NONAME
    EAI_OVERFLOW
    EAI_SERVICE
    EAI_SOCKTYPR
    EAI_SYSTEM

void freeaddrinfo(struct addrinfo* res);

  Получение имени хоста по адрессу

struct	hostent *  gethostbyaddr(const char * addr, // IP address
                 int  len,	    // Len of address
                 int  type);	    // AF_INET or AF_INET6
    // Retrive information about host by it's address
    // Return hostent if success
    // NULL if fail
    // hostent is one-per-thread static buffer
    // DO NOT MODIFY THIS hostent

struct hostent	* gethostbyaddr_r(const char *,
                  int,
                  int,
                  struct hostent *,
                  char *,
                  int,
                  int *h_errnop);

int	getnameinfo(struct sockaddr* addr,
            socklen_t  addrlen,
            char*  hostname,
            size_t hostlen,
            char*  servicename,
            size_t servicelen,
            int    flags);
            NI_DGRAM
            NI_NAMEREQD
            NI_NOFQDN
            NI_NUMERICHOST
            NI_NUMERICSERV

  Записи о сервисах

struct servent * getservbyname(const char * name,   // Name of service
                   const char * proto); // Name of protocol
    // Get information about well-known service on local computer
    // by service name
    // return servent from per-thread static buffer or
    //       NULL if can't get this info
    // DO NOT MODIFY THIS servent

struct servent
    {
        char *	s_name;		// Service name
        char ** s_aliases;	// Aliase service name
        short	s_port;         // Port number   (Network format)
        char *	s_proto;        // protocol name

    };

struct servent * getservbyport(int port,	     // Port (Network format)
                   const char * proto);  // Name of protocol
    // Get information about well-known service on local computer
    // by port number.
    // return servent (per-thread static buffer) or
    //       NULL if can't get this info
    // DO NOT MODIFY THIS servent

    getservbyname_r
    getservbyport_r

    endservent
    setservent
    getservent
    getservent_r

  Записи о протоколах

    getprotobyname
    getprotobynumber

    getprotobyname_r
    getprotobynumber_r

    endprotoent
    setprotoent
    getprotoent
    getprotoent_r

  Записи о хостах

    gethostent
    gethostent_r
    endhostent
    sethostent

  Записи о сетях

    getnetbyaddr
    getnetbyname
    getnetbyname_r
    getnetbyaddr_r

    setnetent
    getnetent
    endnetent
    getnetent_r

    setnetgrent
    getnetgrent
    endnetgrent
    getnetgrent_r

  Преобразования адрессов из текстового вида в бинарный и обратно

А также преобразования адресов из текствого вида в бинарный и обратно.

// arpa\inet.h

const char* inet_ntop(int family, const void* address, char* dest, int size);
int	    inet_pton(int family, const char* address, void* dest);

// IPv4 only
char*     inet_ntoa(struct in_addr address);
unsigned  long int inet_addr(const char* ddaddress);
int       inet_aton(const char* ddaddress, struct in_addr* address);


81.4.14. ПОЛЬЗОВАТЕЛЬСКИЕ API ДЛЯ СЕТЕВЫХ КОММУНИКАЦИЙ

THIS SECTION IS UNDER CONSTRUCTION

Пользовательские API для сетевых коммуникаций

    sockets - de facto для TCP/IP

опять таки - два типа коммуникаций
    connection-oriented
    connection-less

    stream
    ordered datagrams
    unordered datagrams

    SOCK_STREAM
    SOCK_DGRAM
    SOCK_RAW
    SOCK_PACKET

TODO: картинки sendto/recvfrom/select

Main socket interface:
    socket
    bind
    listen
    accept
    connect
    select

    send
    recv

    sendto
    recvfrom

    sendmsg
        MSG_DONTROUTE
        MSG_OOB
        MSG_DONTWAIT
    recvmsg
        MSG_DONTWAIT
        MSG_OOB
        MSG_PEEK
        MSG_WAIT_ALL
        MSG_BCAST
        MSG_MCAST
        MSG_TRUNC
        MSG_CTRUNC

    setsockopt
    getsockopt
        SOL_SOCKET
            SO_BINDTODEVICE
            SO_BROADCAST
            SO_DONTROUTE
            SO_ERROR
            SO_KEEPALIVE
            SO_LINGER
            SO_OOBINLINE
            SO_PRIORITY
            SO_RCVBUF
            SO_REUSEADDR
            SO_RCVLOWAT
            SO_RCVTIMEO
            SO_REUSEPORT
            SO_SNDBUF
            SO_SNDLOWAT
            SO_SNDTIMEO
            SO_TYPE
        IPPROTO_IP
            IP_HDRINCL
            IP_OPTIONS
            IP_RECVDSTADDR
            IP_RECVIF
            IP_TOS
            IP_TTL
            IP_ADD_MEMBERSHIP
            IP_DROP_MEMBERSHIP
            IP_MULTICAST_IF
            IP_MULTICAST_LOOP
            IP_MULTICAST_TTL
        IPPROTO_TCP
            TCP_KEEPALIVE
            TCP_MAXRT
            TCP_MAXSEG
            TCP_NODELAY
            TCP_STDURG

    getsockname
    getperrname

    shutdown

    socketpair

    htons/htonl/ntohs/ntohl
    inet_addr
    inet_ntoa
    inet_ntop
    inet_pton

    sockatmark


81.4.14.1. API ДЛЯ РАБОТЫ С MULTICAST

THIS SECTION IS UNDER CONSTRUCTION

IP_MULTICAST_IF
IP_MULTICAST_TTL
IP_MULTICAST_LOOP
IP_ADD_MEMBERSHIP
IP_DROP_MEMBERSHIP

IPV6_MULTICAST_IF
IPV6_MULTICAST_HOPS
IPV6_MULTICAST_LOOP
IPV6_ADD_MEMBERSHIP
IPV6_DROP_MEMBERSHIP
IPV6_JOIN_GROUP
IPV6_LEAVE_GROUP


81.4.14.2. API ДЛЯ РАБОТЫ С QoS

THIS SECTION IS UNDER CONSTRUCTION


81.4.15. ПОЛЬЗОВАТЕЛЬСКИЕ API ДЛЯ УПРАВЛЕНИЯ СЕТЬЮ

THIS SECTION IS UNDER CONSTRUCTION

    Network intefrface management
    Local-link Address Resolution management
    Address Management
    Routing Management
    Internet protocol and ICMP Management

Управление сетевыми интерфейсами:
        Перечисление сетевых интерфейсов
    Получение/установка свойств сетевых интерфейсов
        MAC адресс
        MTU
        Тип сетевого окружения
    Управление интерфейсами
        Start/Stop
        Режимы работы
            Limited Multicast
            All Multicast
            Promiscous mode
            итд

Разрешение локальных адрессов
    Добавить статический вход в ARP таблицу
    Удалить статический вход из ARP таблицы
    Получить ARP таблицу
    Инициировать выполнение ARP запроса
    Сбросить ARP таблицу

Управление Адрессами
    Добавить сетевой адресс
    Удалить сетевой адресс
    Получить таблицу сетевых адрессов
    Динамически получить сетевой адресс
    Отпустить динамически полученный адресс

Управление маршрутизацией
    Создать статическую запись в таблице маршрутизации
    Удалить статическую запись в таблице маршрутизации
    Обновить статическую запись в таблице маршрутизации
    Получить таблицу маршрутизации
    Получить интерфейс для target address
    Получить best route для target address
    Запретить router
    Разрешить router

Управление конкретными протоколами
    Получить статистику
    Получить/установить параметры
        например TTL по умолчанию

THIS SECTION IS UNDER CONSTRUCTION


81.4.15.1. УПРАВЛЕНИЕ СЕТЕВЫМИ ИНТЕРФЕЙСАМИ

THIS SECTION IS UNDER CONSTRUCTION

Windows IpHelper

Adapter Management:
    GetAdapterIndex()
    GetAdaptersAddresses()
    GetAdaptersInfo()
    GetPerAdapterInfo()
    GetUniDirectionalAdapterInfo()

Interface Management:
    GetFriendlyIfIndex()
    GetIfEntry()
    GetIfTable()
    GetInterfaceInfo()
    GetNumberOfInterfaces()
    SetIfEntry()


81.4.15.2. РАЗРЕШЕНИЕ ЛОКАЛЬНЫХ АДРЕССОВ

THIS SECTION IS UNDER CONSTRUCTION

Windows IpHelper

Address Resolution Protocol:
    CreateIpNetEntry()
    CreateProxyArpEntry()
    DeleteIpNetEntry()
    DeleteProxyArpEntry()
    FlushIpNetTable()
    GetIpNetTable()
    SendARP()
    SetIpNetEntry()


81.4.15.3. УПРАВЛЕНИЕ ЛОКАЛЬНЫМИ АДРЕССАМИ

THIS SECTION IS UNDER CONSTRUCTION

Windows IpHelper
IP Address Management:
    AddIPAddress()
    DeleteIPAddress()
    GetIpAddrTable()
    IpReleaseAddress()
    IpRenewAddress()


81.4.15.4. УПРАВЛЕНИЕ МАРШРУТИЗАЦИЕЙ

THIS SECTION IS UNDER CONSTRUCTION

  Работа компьютера как маршрутизатора

  Управление таблицами маршрутизации

Windows IpHelper
Routing:
    CreateIpForwardEntry()
    DeleteIpForwardEntry()
    EnableRouter()
    GetBestInterface()
    GetBestRoute()
    GetIpForwardTable()
    GetRTTAndHopCount()
    SetIpForwardEntry()
    UnenableRouter()


81.4.15.5. УПРАВЛЕНИЕ КОНКРЕТНЫМИ ПРОТОКОЛАМИ

THIS SECTION IS UNDER CONSTRUCTION

Windows IpHelper
Internet Protocol and Internet Control Message Protocol:
    GetIcmpStatistics()
    GetIpStatistics()
    IcmpCloseHandle()
    IcmpCreateFile()
    IcmpParseReplies()
    IcmpSendEcho()
    IcmpSendEcho2()
    SetIpStatistics()
    SetIpTTL()
Transmission Control Protocol and User Datagram Protocol:
    GetTcpStatistics()
    GetTcpTable()
    SetTcpEntry()
    GetUdpStatistics()
    GetUdpTable()


81.4.16. СЕТЕВЫЕ СЕРВИСЫ

THIS SECTION IS UNDER CONSTRUCTION


81.4.17. ПРИМЕРЫ КЛАССОВ ДЛЯ РАБОТЫ С СЕТЬЮ

THIS SECTION IS UNDER CONSTRUCTION

  MFC

  CAsyncSocket

class CAsyncSocket : public CObject
{
    DECLARE_DYNAMIC(CAsyncSocket);
private:
    CAsyncSocket(const CAsyncSocket& rSrc);    // no implementation
    void operator=(const CAsyncSocket& rSrc);  // no implementation

public:
    CAsyncSocket();
    BOOL Create(UINT nSocketPort = 0, int nSocketType=SOCK_STREAM,
        long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
        LPCTSTR lpszSocketAddress = NULL);

public:
    SOCKET m_hSocket;

    operator SOCKET() const;
    BOOL Attach(SOCKET hSocket, long lEvent =
        FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
    SOCKET Detach();

    BOOL GetPeerName(CString& rPeerAddress, UINT& rPeerPort);
    BOOL GetPeerName(SOCKADDR* lpSockAddr, int* lpSockAddrLen);

    BOOL GetSockName(CString& rSocketAddress, UINT& rSocketPort);
    BOOL GetSockName(SOCKADDR* lpSockAddr, int* lpSockAddrLen);

    BOOL SetSockOpt(int nOptionName, const void* lpOptionValue,
        int nOptionLen, int nLevel = SOL_SOCKET);
    BOOL GetSockOpt(int nOptionName, void* lpOptionValue,
        int* lpOptionLen, int nLevel = SOL_SOCKET);

    static CAsyncSocket* PASCAL FromHandle(SOCKET hSocket);
    static int PASCAL GetLastError();

public:

    virtual BOOL Accept(CAsyncSocket& rConnectedSocket,
        SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL);

    BOOL Bind(UINT nSocketPort, LPCTSTR lpszSocketAddress = NULL);
    BOOL Bind (const SOCKADDR* lpSockAddr, int nSockAddrLen);

    virtual void Close();

    BOOL Connect(LPCTSTR lpszHostAddress, UINT nHostPort);
    BOOL Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen);

    BOOL IOCtl(long lCommand, DWORD* lpArgument);

    BOOL Listen(int nConnectionBacklog=5);

    virtual int Receive(void* lpBuf, int nBufLen, int nFlags = 0);

    int ReceiveFrom(void* lpBuf, int nBufLen,
        CString& rSocketAddress, UINT& rSocketPort, int nFlags = 0);
    int ReceiveFrom(void* lpBuf, int nBufLen,
        SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags = 0);

    enum { receives = 0, sends = 1, both = 2 };
    BOOL ShutDown(int nHow = sends);

    virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);

    int SendTo(const void* lpBuf, int nBufLen,
        UINT nHostPort, LPCTSTR lpszHostAddress = NULL, int nFlags = 0);
    int SendTo(const void* lpBuf, int nBufLen,
        const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags = 0);

    BOOL AsyncSelect(long lEvent =
        FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);

// Overridable callbacks
protected:
    virtual void OnReceive(int nErrorCode);
    virtual void OnSend(int nErrorCode);
    virtual void OnOutOfBandData(int nErrorCode);
    virtual void OnAccept(int nErrorCode);
    virtual void OnConnect(int nErrorCode);
    virtual void OnClose(int nErrorCode);

public:
    virtual ~CAsyncSocket();

    static CAsyncSocket* PASCAL LookupHandle(SOCKET hSocket, BOOL bDead = FALSE);
    static void PASCAL AttachHandle(SOCKET hSocket, CAsyncSocket* pSocket, BOOL bDead = FALSE);
    static void PASCAL DetachHandle(SOCKET hSocket, BOOL bDead = FALSE);
    static void PASCAL KillSocket(SOCKET hSocket, CAsyncSocket* pSocket);
    static void PASCAL DoCallBack(WPARAM wParam, LPARAM lParam);

    BOOL Socket(int nSocketType=SOCK_STREAM, long lEvent =
        FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
        int nProtocolType = 0, int nAddressFormat = PF_INET);

protected:
    friend class CSocketWnd;

    virtual BOOL ConnectHelper(const SOCKADDR* lpSockAddr, int nSockAddrLen);
    virtual int ReceiveFromHelper(void* lpBuf, int nBufLen,
        SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags);
    virtual int SendToHelper(const void* lpBuf, int nBufLen,
        const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags);
};

  CSocket

class CSocket : public CAsyncSocket
{
    DECLARE_DYNAMIC(CSocket);
private:
    CSocket(const CSocket& rSrc);         // no implementation
    void operator=(const CSocket& rSrc);  // no implementation

public:
    CSocket();
    BOOL Create(UINT nSocketPort = 0, int nSocketType=SOCK_STREAM,
        LPCTSTR lpszSocketAddress = NULL);

public:
    BOOL IsBlocking();
    static CSocket* PASCAL FromHandle(SOCKET hSocket);
    BOOL Attach(SOCKET hSocket);

public:
    void CancelBlockingCall();

// Overridable callbacks
protected:
    virtual BOOL OnMessagePending();

public:
    int m_nTimeOut;

    virtual ~CSocket();

    static int PASCAL ProcessAuxQueue();

    virtual BOOL Accept(CAsyncSocket& rConnectedSocket,
        SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL);
    virtual void Close();
    virtual int Receive(void* lpBuf, int nBufLen, int nFlags = 0);
    virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);

    int SendChunk(const void* lpBuf, int nBufLen, int nFlags);

protected:
    friend class CSocketWnd;

    BOOL* m_pbBlocking;
    int m_nConnectError;

    virtual BOOL ConnectHelper(const SOCKADDR* lpSockAddr, int nSockAddrLen);
    virtual int ReceiveFromHelper(void* lpBuf, int nBufLen,
        SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags);
    virtual int SendToHelper(const void* lpBuf, int nBufLen,
        const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags);

    static void PASCAL AuxQueueAdd(UINT message, WPARAM wParam, LPARAM lParam);

    virtual BOOL PumpMessages(UINT uStopFlag);

};

  CSocketFile

class CSocketFile : public CFile
{
    DECLARE_DYNAMIC(CSocketFile)
public:
    CSocketFile(CSocket* pSocket, BOOL bArchiveCompatible = TRUE);

// Implementation
public:
    CSocket* m_pSocket;
    BOOL m_bArchiveCompatible;

    virtual ~CSocketFile();

    virtual UINT Read(void* lpBuf, UINT nCount);
    virtual void Write(const void* lpBuf, UINT nCount);
    virtual void Close();

// Unsupported APIs
    virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL);
    virtual CFile* Duplicate() const;
    virtual DWORD GetPosition() const;
    virtual LONG Seek(LONG lOff, UINT nFrom);
    virtual void SetLength(DWORD dwNewLen);
    virtual DWORD GetLength() const;
    virtual void LockRange(DWORD dwPos, DWORD dwCount);
    virtual void UnlockRange(DWORD dwPos, DWORD dwCount);
    virtual void Flush();
    virtual void Abort();
};

  Qt

In Qt this classes located in QNetwork module

class QAbstractSocket : QIODevice
{
public:
    enum NetworkLayerProtocol
    {
        IPv4Protocol,
        IPv6Protocol,
        UnknownNetworkLayerProtocol
    };

    enum SocketError
    {
        ConnectionRefusedError,
        RemoteHostClosedError,
        HostNotFoundError,
        SocketAccessError,
        ...,
        UnknownSocketError
    };

    enum SocketState
    {
        UnconnectedState,
        HostLookupState,
        ConnectingState,
        ConnectedState,
        ...,
        ListeningState
    };

    enum SocketType
    {
        TcpSocket,
        UdpSocket,
        UnknownSocketType
    };

    QAbstractSocket ( SocketType socketType, QObject * parent );
    virtual ~QAbstractSocket ();
    void abort ();
    virtual qint64 bytesAvailable () const;
    virtual qint64 bytesToWrite () const;
    virtual bool canReadLine () const;
    virtual void close ();
    void connectToHost ( const QString & hostName, quint16 port,
                 OpenMode openMode = ReadWrite );
    void connectToHost ( const QHostAddress & address, quint16 port,
                 OpenMode openMode = ReadWrite );
    void disconnectFromHost ();
    SocketError error () const;
    bool flush ();
    bool isValid () const;
    QHostAddress localAddress () const;
    quint16 localPort () const;
    QHostAddress peerAddress () const;
    QString peerName () const;
    quint16 peerPort () const;
    QNetworkProxy proxy () const;
    qint64 readBufferSize () const;
    void setProxy ( const QNetworkProxy & networkProxy );
    void setReadBufferSize ( qint64 size );
    bool setSocketDescriptor ( int socketDescriptor,
        SocketState socketState = ConnectedState, OpenMode openMode = ReadWrite );
    int socketDescriptor () const;
    SocketType socketType () const;
    SocketState state () const;
    bool waitForConnected ( int msecs = 30000 );
    bool waitForDisconnected ( int msecs = 30000 );

public signals:
    void connected ();
    void disconnected ();
    void error ( QAbstractSocket::SocketError socketError );
    void hostFound ();
    void stateChanged ( QAbstractSocket::SocketState socketState );

protected:
    void setLocalAddress ( const QHostAddress & address );
    void setLocalPort ( quint16 port );
    void setPeerAddress ( const QHostAddress & address );
    void setPeerName ( const QString & name );
    void setPeerPort ( quint16 port );
    void setSocketError ( SocketError socketError );
    void setSocketState ( SocketState state );

protected slots:

    void connectToHostImplementation ( const QString & hostName, quint16 port,
                OpenMode openMode = ReadWrite );
    void disconnectFromHostImplementation ();
};

class QUdpSocket : QAbstractSocket
{
public:
    enum BindFlag
    {
        ShareAddress,
        DontShareAddress,
        ReuseAddressHint,
        DefaultForPlatform
    } flags BindMode;

    QUdpSocket ( QObject * parent = 0 );
    virtual ~QUdpSocket ();
    bool bind ( const QHostAddress & address, quint16 port );
    bool bind ( const QHostAddress & address, quint16 port, BindMode mode );
    bool bind ( quint16 port = 0 );
    bool bind ( quint16 port, BindMode mode );
    bool hasPendingDatagrams () const;
    qint64 pendingDatagramSize () const;
    qint64 readDatagram ( char * data, qint64 maxSize,
                  QHostAddress * address = 0, quint16 * port = 0 );
    qint64 writeDatagram ( const char * data, qint64 size,
                  const QHostAddress & address, quint16 port );
    qint64 writeDatagram ( const QByteArray & datagram, const QHostAddress & host,
                  quint16 port );
};

class QTcpSocket : QAbstractSocket
{
public:
    QTcpSocket ( QObject * parent = 0 );
    virtual ~QTcpSocket ();
};

class QTcpServer : QObject
{
public:

    QTcpServer ( QObject * parent = 0 );
    virtual ~QTcpServer ();
    void close ();
    QString errorString () const;
    virtual bool hasPendingConnections () const;
    bool isListening () const;
    bool listen ( const QHostAddress & address = QHostAddress::Any, quint16 port = 0 );
    int maxPendingConnections () const;
    virtual QTcpSocket * nextPendingConnection ();
    QNetworkProxy proxy () const;
    QHostAddress serverAddress () const;
    QAbstractSocket::SocketError serverError () const;
    quint16 serverPort () const;
    void setMaxPendingConnections ( int numConnections );
    void setProxy ( const QNetworkProxy & networkProxy );
    bool setSocketDescriptor ( int socketDescriptor );
    int socketDescriptor () const;
    bool waitForNewConnection ( int msec = 0, bool * timedOut = 0 );

public signals:
    void newConnection ();

protected:
    virtual void incomingConnection ( int socketDescriptor );
};

class QNetworkInterface
{
public:
    enum InterfaceFlag
    {
        IsUp,
        IsRunning,
        CanBroadcast,
        IsLoopBack,
        IsPointToPoint,
        CanMulticast
    } flags InterfaceFlags;

    QNetworkInterface ();
    QNetworkInterface ( const QNetworkInterface & other );
    ~QNetworkInterface ();
    QList<QNetworkAddressEntry> addressEntries () const;
    InterfaceFlags flags () const;
    QString hardwareAddress () const;
    bool isValid () const;
    QString name () const;
    QNetworkInterface & operator= ( const QNetworkInterface & other );

static QList<QHostAddress> allAddresses ();
static QList<QNetworkInterface> allInterfaces ();
static QNetworkInterface interfaceFromIndex ( int index );
static QNetworkInterface interfaceFromName ( const QString & name );
};

class  QNetworkAddressEntry
{
public:
    QNetworkAddressEntry ()
    QNetworkAddressEntry ( const QNetworkAddressEntry & other )
    ~QNetworkAddressEntry ();
    QHostAddress broadcast () const;
    QHostAddress ip () const;
    QHostAddress netmask () const;
    void setBroadcast ( const QHostAddress & newBroadcast );
    void setIp ( const QHostAddress & newIp );
    void setNetmask ( const QHostAddress & newNetmask );
    QNetworkAddressEntry & operator= ( const QNetworkAddressEntry & other );
};

class QHostAddress
{
public:
    enum SpecialAddress
    {
        Null,
        LocalHost,
        LocalHostIPv6,
        Broadcast,
        Any,
        AnyIPv6
    };

    QHostAddress ();
    QHostAddress ( quint32 ip4Addr );
    QHostAddress ( quint8 * ip6Addr );
    QHostAddress ( const Q_IPV6ADDR & ip6Addr );
    QHostAddress ( const sockaddr * sockaddr );
    QHostAddress ( const QString & address );
    QHostAddress ( const QHostAddress & address );
    QHostAddress ( SpecialAddress address );
    ~QHostAddress ();
    void clear ();
    bool isNull () const;
    QAbstractSocket::NetworkLayerProtocol protocol () const;
    QString scopeId () const;
    void setAddress ( quint32 ip4Addr );
    void setAddress ( quint8 * ip6Addr );
    void setAddress ( const Q_IPV6ADDR & ip6Addr );
    bool setAddress ( const QString & address );
    void setAddress ( const sockaddr * sockaddr );
    void setScopeId ( const QString & id );
    quint32 toIPv4Address () const;
    Q_IPV6ADDR toIPv6Address () const;
    QString toString () const;
    bool operator!= ( const QHostAddress & other ) const;
    bool operator!= ( SpecialAddress other ) const;
    QHostAddress & operator= ( const QHostAddress & address );
    QHostAddress & operator= ( const QString & address );
    bool operator== ( const QHostAddress & other ) const;
    bool operator== ( SpecialAddress other ) const;
};

class QHostInfo
{
public:
    enum HostInfoError
    {
        NoError,
        HostNotFound,
        UnknownError
    };

    QHostInfo ( int id = -1 );
    QHostInfo ( const QHostInfo & other );
    ~QHostInfo ();
    QList<QHostAddress> addresses () const;
    HostInfoError error () const;
    QString errorString () const;
    QString hostName () const;
    int lookupId () const;
    void setAddresses ( const QList<QHostAddress> & addresses );
    void setError ( HostInfoError error );
    void setErrorString ( const QString & str );
    void setHostName ( const QString & hostName );
    void setLookupId ( int id );
    QHostInfo & operator= ( const QHostInfo & other );

static  void abortHostLookup ( int id );
static  QHostInfo fromName ( const QString & name );
static  QString localHostName ();
static  int lookupHost ( const QString & name, QObject * receiver, const char * member );
};


81.5. УПРАВЛЕНИЕ ПОТОКАМИ И ПРОЦЕССАМИ

THIS SECTION IS UNDER CONSTRUCTION

Группы процессов (задания)
    используется для управления

Экранная группа
    разделяет одну консоль (управляющий терминал)

Процессы
    владельцы ресурсов
        memory (virtual)
        environment
        other resources (files etc)

Потоки
    владельцы ресурса CPU
        Static priority
        Dynamic priority
        Scheduling class (FIFO, RR, other)
                Sporadic time
                deadline
                Rate Monolythic Analysis

Волокна (Fiber)
    переключаются не автоматически, а по запросу

О синхронизации между нитями и процессами можно прочитать в секции
82.1. ПРИМИТИВЫ СИНХРОНИЗАЦИИ

Scheduling
    распределение процессорного времени (ресурса)

        Приоритетное
        Адаптивное (добавляем 1)
        Deadline-driven

    Проблема инверсии приоритетов

        Потоки H (high-priority) и L (Low-priority) разделяют ресурс P
        T - третий поток (средний приоритет)

        Если H ready, когда активен L, и L заблокировал P,
        то H вытеснит L.

        Как только H захочет ресурс P, то заблокируется.
        Если в это время готов T, то будет выполнсться он а не L.
        Как результат - получаем что H ждет долго

    Решение - наследование приоритетов:
        Если L блокировал ресурс P, который нужен H,
        то при блокировании H, приоритет L повышается до H.

    Решение - Priority Ceiling Protocol
            Приоритет любого потока обращающегося к объекту
            повышается до указанного уровня.


81.5.0. ГРУППЫ ПРОЦЕССОВ

  Задания Windows

Задание - группа процессов (цель объединения: management)

 Windows

HANDLE WINAPI CreateJobObject(
  __in          LPSECURITY_ATTRIBUTES lpJobAttributes,
  __in          LPCTSTR lpName
);

HANDLE WINAPI OpenJobObject(
  __in          DWORD dwDesiredAccess,
  __in          BOOL bInheritHandles,
  __in          LPCTSTR lpName
);

BOOL WINAPI SetInformationJobObject(
  __in          HANDLE hJob,
  __in          JOBOBJECTINFOCLASS JobObjectInfoClass,
  __in          LPVOID lpJobObjectInfo,
  __in          DWORD cbJobObjectInfoLength
);
    // Informationclass is:
    //  set
    //	JobObjectAssociateCompletionPortInformation
    //	JobObjectBasicLimitInformation
    //	JobObjectBasicUIRestrictions
    //	JobObjectEndOfJobTimeInformation
    //	JobObjectExtendedLimitInformation
    //	JobObjectSecurityLimitInformation
    // get
    //	JobObjectBasicAccountingInformation
    //	JobObjectBasicAndIoAccountingInformation
    //	JobObjectBasicLimitInformation
    //	JobObjectBasicProcessIdList
    //	JobObjectBasicUIRestrictions
    //	JobObjectExtendedLimitInformation
    //	JobObjectSecurityLimitInformation

BOOL WINAPI QueryInformationJobObject(
  __in          HANDLE hJob,
  __in          JOBOBJECTINFOCLASS JobObjectInfoClass,
  __out         LPVOID lpJobObjectInfo,
  __in          DWORD cbJobObjectInfoLength,
  __out         LPDWORD lpReturnLength
);

BOOL WINAPI AssignProcessToJobObject(
  __in          HANDLE hJob,
  __in          HANDLE hProcess
);

BOOL WINAPI IsProcessInJob(
  __in          HANDLE ProcessHandle,
  __in          HANDLE JobHandle,
  __out         PBOOL Result
);

BOOL WINAPI TerminateJobObject(
  __in          HANDLE hJob,
  __in          UINT uExitCode
);

  Группы процессов UNIX

Process group:

Группа процессов

Сессия - коллекция из одной или более групп процессов
     имеет управляющий терминал
     точно 1 группа foreground процессов
     0 или более групп background процессов

    tcgetpgrp	Определяют какой группе будет ввод с терминала
    tcsetpgrp
    tcgetsid

    killpg

    getpgrp
    getpgid
    setpgid
    setpgrp

    Leader of group:  PID = PGRP

    setsid		// session ID
    getsid

 UNIX

// unistd.h

pid_t  setsid(void);

int    setpgid(pid_t pid, pid_t pgid);

pid_t  getprgid(pid_t pid);
pid_t  getpgrp(void)


81.5.1. ПРОЦЕССЫ

THIS SECTION IS UNDER CONSTRUCTION

  Процессы

Разница между процессом и программой

  Запуск нового процесса

    Запуск нового процесса
        system
        popen
        fork
        fork + exec

Права доступа на процесс
    PROCESS_TERMINATE
    PROCESS_CREATE_THREAD
    PROCESS_SET_SESSIONID
    PROCESS_VM_OPERATION
    PROCESS_VM_READ
    PROCESS_VM_WRITE
    PROCESS_DUP_HANDLE
    PROCESS_CREATE_PROCESS
    PROCESS_SET_QUITA
    PROCESS_SET_INFORMATION
    PROCESS_QUERY_INFORMATION

семейство функций exec и spawn

    getpid
    fork
        -1  error
        0   child
        pid parent

Solaris
    fork()		все нети
    fork1()         только та которая выполнила fork1()

pid  = wait(&status)

 UNIX

pid_t  wait(int* status);
pid_t  waitpid(pid_t pid, int* status, int options);
pid_t  wait3(int* status, int options, struct rusage* rusage);
pid_t  wait4(pid_t pid, int* status, int options, struct rusage* rusage);
    // status can be check using

    WIFEXITED(status)
    WIFSIGNALED(status)
    WIFSTOPPED(status)

    _exit
        Close all file and dir descriptors
        Change PPID on all of child processes
        notify parent if it call wait() or waitpid()
        send SIGCHLD to parent

    execv(char* filename,char* argv[]);

 UNIX

int    execl(char* pathname, ...);	// arg0,...,argN,NULL
int    execle(char* pathname, ...);  // arg0,...,argN,NULL,env
int    execlp(char* pathname, ...);	// arg0,...,argN,NULL
int    execlpe(char* pathname, ...);  // arg0,...,argN,NULL,env

int	execl(const char*  filename,
          const char*  arg,
           ...);

int	execlp(const char* pathname,
           const char* arg,
        ...);

int	execle(const char* path,
           const char* arg,
           ...,
           char* const envp[]);

int	execve(const char* filename,
           char* const argv[],
           char* const envp[]);

int    execv(char* filename, char* argv[]);
int    execve(char* filename, char* argv[], char* env[]);
int    execvp(char* pathname, char* argv[]);
int    execvpe(char* pathname, char* argv[], char* env[]);

execl("/bin/cat", "/bin/cat", "/etc/password", "/etc/group", NULL);

char*  newenv[] =
{
    "PATH=/bin:/usr/bin",
    "HOME=/home",
    NULL
};

if ((pod = fork()) == 0)
{
    execve("foo");
} else {
    waitpid(pid);
}

    vfork()		parent blocked until child call exit() or exec()

int clone(int (*fn)(void(), void* child_stack, int flags, void* arg)

clone()
    CLONE_FILES
    CLONE_FS
    CLONE_IDLETASK
    CLONE_NEWFS
    CLONE_PARENT
    CLONE_PTRACE
    CLONE_SETTID
    CLONE_SETTLS
    CLONE_SEGHAND
    CLONE_SYSVSEM
    CLONE_THREAD
    CLONE_VFORK
    CLONE_UNTRACED
    CLONE_STOP
    CLONE_CHILD_CLEARTID
    CLONE_CHILD_SETTID
    CLONE_PARENT_SETTID
    CLONE_VM

fork
    clone(SIGCHLD, 0)

vfork
    clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

запуск потока

    clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLOSE_SIGHAND, 0)

FreeBSD rfork

    pid_t  rfork(int flags);
        // flags:
        //	RFPROC		создать новый процесс
        //	RFNOWAIT        диассоцировать процесс от родителя
        //	RFFDG		копировать таблицу дескрипторов
                    (если не копировать - то она шариться)
        //	RFTHREAD
        //	RFMEM
        //	RFSIGSHARE	шарит sigact между процессами
        //	RFLINUXTHPN	SIGUSR1 instead of SIGCHILD

    fcntl(fd, F_SETFD, 1);	// установка флага close-on-exec
                       FD_CLOEXEC

    У родителя и потомка разные PID

    fork	родитель сохраняет file locks
        child - не сохраняет file locks
    exec	file locks сохраняются

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

QNX

//spawn.h
       pid_t	spawn(const char * path,
            int fd_count,
            const int fd_map[],
            const struct inheritance* inherit,
            char* const argv[],
            char* const envp[]);

int    spawnl(int mode, char* pathname, ...);	// arg0,...,argN,NULL
int    spawnle(int mode, char* pathname, ...);  // arg0,...,argN,NULL,env
int    spawnlp(int mode, char* pathname, ...);	// arg0,...,argN,NULL
int    spawnlpe(int mode, char* pathname, ...);  // arg0,...,argN,NULL,env

int    spawnv(int mode, char* pathname, char* argv[]);
int    spawnve(int mode, char* pathname, char* argv[], char* env[]);
int    spawnvp(int mode, char* pathname, char* argv[]);
int    spawnvpe(int mode, char* pathname, char* argv[], char* env[]);
    // mode is:
    //	P_WAIT
    //	P_NOWAIT
    //	P_OVERLAY

int system(const char* cmd);
    //  /bin/sh

 Windows

BOOL WINAPI CreateProcess(
      __in          LPCTSTR lpApplicationName,
      __in_out      LPTSTR lpCommandLine,
      __in          LPSECURITY_ATTRIBUTES lpProcessAttributes,
      __in          LPSECURITY_ATTRIBUTES lpThreadAttributes,
      __in          BOOL bInheritHandles,
      __in          DWORD dwCreationFlags,
      __in          LPVOID lpEnvironment,
      __in          LPCTSTR lpCurrentDirectory,
      __in          LPSTARTUPINFO lpStartupInfo,
      __out         LPPROCESS_INFORMATION lpProcessInformation
    );

    typedef struct _STARTUPINFO
    {
        DWORD cb;
        LPTSTR lpReserved;
        LPTSTR lpDesktop;
        LPTSTR lpTitle;
        DWORD dwX;
        DWORD dwY;
        DWORD dwXSize;
        DWORD dwYSize;
        DWORD dwXCountChars;
        DWORD dwYCountChars;
        DWORD dwFillAttribute;
        DWORD dwFlags;
        WORD wShowWindow;
        WORD cbReserved2;
        LPBYTE lpReserved2;
        HANDLE hStdInput;
        HANDLE hStdOutput;
        HANDLE hStdError;
    } STARTUPINFO,  *LPSTARTUPINFO;

    typedef struct _PROCESS_INFORMATION
    {
        HANDLE hProcess;
        HANDLE hThread;
        DWORD dwProcessId;
        DWORD dwThreadId;
    } PROCESS_INFORMATION,  *LPPROCESS_INFORMATION;

BOOL WINAPI CreateProcessAsUser(
      __in          HANDLE hToken,
      __in          LPCTSTR lpApplicationName,
      __in          LPTSTR lpCommandLine,
      __in          LPSECURITY_ATTRIBUTES lpProcessAttributes,
      __in          LPSECURITY_ATTRIBUTES lpThreadAttributes,
      __in          BOOL bInheritHandles,
      __in          DWORD dwCreationFlags,
      __in          LPVOID lpEnvironment,
      __in          LPCTSTR lpCurrentDirectory,
      __in          LPSTARTUPINFO lpStartupInfo,
      __out         LPPROCESS_INFORMATION lpProcessInformation
    );

  Завершение процесса

    ExitProcess
    GetExitCodeProcess
    TerminateProcess

 Windows

VOID WINAPI ExitProcess(UINT uExitCode);

BOOL WINAPI GetExitCodeProcess(
  __in          HANDLE hProcess,
  __out         LPDWORD lpExitCode
);

BOOL WINAPI TerminateProcess(
  __in          HANDLE hProcess,
  __in          UINT uExitCode
);

 UNIX

void _exit(int exitcode);	// System call
void exit(int exitcode);	// C RTL

int atexit(void (*function)(void));
int kill(pid_t pid, int signum);

  Идентификация и самоидентификация процессов

 Windows

HANDLE WINAPI GetCurrentProcess(void);	// возращает fake handle,
                    // для получение реального надо вызвать
                    // DuplicateHandle

DWORD WINAPI GetCurrentProcessId(void);

HANDLE WINAPI OpenProcess(
  __in          DWORD dwDesiredAccess,
  __in          BOOL bInheritHandle,
  __in          DWORD dwProcessId
);

 UNIX

pid_t	getpid(void);		// process PID
pid_t	getppid(void);		// process parent PID

 UNIX

// Linux

    _SC_NGROUPS_MAX
            2.4	32
            2.6	65536

int	setgroups(size_t  num, const gid_t* list);
int	getgroups(size_t  num, gid_t* list);

 UNIX

// Linux
int	setfsuid(uid_t uid);
int	setfsgid(gid_t gid);

  Управление scheduling процесса

 Windows

DWORD WINAPI GetPriorityClass(
  __in          HANDLE hProcess
);

BOOL WINAPI SetPriorityClass(
  __in          HANDLE hProcess,
  __in          DWORD dwPriorityClass
);

    // ABOVE_NORMAL_PRIORITY_CLASS
    // BELOW_NORMAL_PRIORITY_CLASS
    // HIGH_PRIORITY_CLASS
    // IDLE_PRIORITY_CLASS
    // NORMAL_PRIORITY_CLASS
    // PROCESS_MODE_BACKGROUND_BEGIN
    // PROCESS_MODE_BACKGROUND_END
    // REALTIME_PRIORITY_CLASS

BOOL WINAPI GetProcessAffinityMask(
  __in          HANDLE hProcess,
  __out         PDWORD_PTR lpProcessAffinityMask,
  __out         PDWORD_PTR lpSystemAffinityMask
);

BOOL WINAPI SetProcessAffinityMask(
  __in          HANDLE hProcess,
  __in          DWORD_PTR dwProcessAffinityMask
);

BOOL WINAPI QueryProcessAffinityUpdateMode(
  __in          HANDLE ProcessHandle,
  __out_opt     DWORD lpdwFlags
);

BOOL WINAPI SetProcessAffinityUpdateMode(
  __in          HANDLE ProcessHandle,
  __in          DWORD dwFlags
);
    PROCESS_AFFINITY_ENABLE_AUTO_UPDATE

BOOL WINAPI GetProcessPriorityBoost(
  __in          HANDLE hProcess,
  __out         PBOOL pDisablePriorityBoost
);

BOOL WINAPI SetProcessPriorityBoost(
  __in          HANDLE hProcess,
  __in          BOOL DisablePriorityBoost
);

UNIX

    nice

 UNIX

// Linux

int	sched_getscheduler(pid_t pid);
int	sched_setscheduler(pid_t pid, int policy, const struct shed_param * sp);
            SCHED_FIFO
            SCHED_RR
            SCHED_OTHER

int	sched_getparam(pid_t pid, struct sched_param* sp);
int	sched_setparam(pid_t pid, const struct sched_param* sp);

int	sched_get_priority_min(int policy);
int	sched_get_priority_max(int policy);

int	sched_rr_get_interval(pid_t pid, struct timespec* tp);

int	sched_setaffinity(pid_t pid, size_t setsize, const cpu_set_t* set);
int	sched_getaffinity(pid_t pid, size_t setsize, cpu_set_t* set);

void	CPU_SET(unsigned long cpu, cpu_set_t* set);
void	CPU_CLR(unsigned long cpu, cpu_set_t* set);
int	CPU_ISSET(unsigned long cpu, cpu_set_t* set);
void	CPU_ZERO(cpu_set_t* set);

    sched_yield

    getpriority
    setpriority
    ioprio_get
    ioprio_set

  Управление имперсонацией

    getuid  	Real
    geteuid		Effective
    getgid		Real
    getegid		Effective

    setuid		Real	(supervisor only)
    setgid		Real	(supervisor only)
    seteuid		Effective
    setegid		Effective

 UNIX

int	setreuid(uid_t rid, uid_t euid);
int	setregid(gid_t rgid, gid_t egid);

  Статистика

 Windows

BOOL WINAPI GetProcessTimes(
  __in          HANDLE hProcess,
  __out         LPFILETIME lpCreationTime,
  __out         LPFILETIME lpExitTime,
  __out         LPFILETIME lpKernelTime,
  __out         LPFILETIME lpUserTime
);

BOOL WINAPI QueryProcessCycleTime(
  __in          HANDLE ProcessHandle,
  __out         PULONG64 CycleTime
);

  Управление квотами процесса

 Windows

BOOL WINAPI GetProcessWorkingSetSize(
  __in          HANDLE hProcess,
  __out         PSIZE_T lpMinimumWorkingSetSize,
  __out         PSIZE_T lpMaximumWorkingSetSize
);

BOOL WINAPI SetProcessWorkingSetSize(
  __in          HANDLE hProcess,
  __in          SIZE_T dwMinimumWorkingSetSize,
  __in          SIZE_T dwMaximumWorkingSetSize
);

    GetProcessWorkingSetSizeEx	// Vista+
    SetProcessWorkingSetSizeEx

 UNIX

// sys/resource.h
int getusage(int who, struct rusage* usage);

struct rusage
{
    struct	timeval	ru_utime;
    struct	timeval	ru_stime;
    long int	ru_maxrss;
    long int	ru_ixrss;
            ru_idrss;
            ru_isrss;
            ru_minflt;
            ru_maxflt;
            ru_nswap;
            ru_inblock;
            ru_oublock;
            ru_msgsnd;
            ru_rsgrcv;
            ru_nsignals;
            ru_nvcsw;
            ru_nivcsw;
};

int  getrlimit(int resource, struct rlimit* rlim);
int  setrlimit(int resource, const struct rlimit* rlim);

struct rlimit
{
    long int rlim_cur;
    long int rlim_max;
};

    RLIMIT_AS
    RLIMIT_MEMLOCK
    RLIMIT_NPROC
    RLIMIT_RSS
    RLIMIT_CORE
    RLIMIT_CPU
    RLIMIT_DATA
    RLIMIT_FSIZE
    RLIMIT_NOFILE
    RLIMIT_STACK

    ulimit

Windows API:

    QueryFullProcessImageName
    QueryProcessAffinityUpdateMode
    SetProcessAffinityUpdateMode
    QueryProcessCycleTime

    WaitForSingleObject
    WaitForSingleObjectEx
    WaitForMultipleObjects
    WaitForMultipleObjectsEx
    SignalObjectAndWait

    InitializeCriticalSection
    TryEnterCriticalSection
    EnterCriticalSection
    LeaveCriticalSection
    DeleteCriticalSection

    TlsAlloc
    TlsFree
    TlsGetValue
    TlsSetValue

    LoadLibrary
    LoadLibraryEx
    FreeLibrary
    FreeLibraryAndExitThread
    GetProcAddress

    waitid

  Перечисление процессов в системе

    EnumProcesses
    Process32First
    Process32Next

  Прочие ресурсы процесса

    GetProcessHeap
    GetProcessHeaps
    GetProcessShutdownParameters
    SetProcessShutdownParameters

DWORD WINAPI GetProcessImageFileName(
  __in          HANDLE hProcess,
  __out         LPTSTR lpImageFileName,
  __in          DWORD nSize
);


81.5.1.1. КОММАНДНАЯ СТРОКА

THIS SECTION IS UNDER CONSTRUCTION

 Windows

LPTSTR WINAPI GetCommandLine(void);

 Windows

// shell32.dll

LPWSTR *CommandLineToArgvW(LPCWSTR lpCmdLine,
               int *pNumArgs);

  РАЗБОР КОМАНДНОЙ СТРОКИ

  Функция main()

int __cdecl main(int argc, char* argv[])
{
    ...
}

int __cdecl main(int argc, char* argv[], char** envp)
{
    ...
}

void  internal_compiler_startup()
{
    init_cpp_static_objects;
    init_library_runtime;
    parse_command_line;
    exit(main(argc,argv));
}

  getopt

// unistd.h

extern	int  opterr;	// if != 0 getopt() print error message to stderr (default)
extern	int  optopt;	// if unknown option or missing argument, option name place here
extern	int  optind;	// index of next element of argv been processed
extern	char* optarg;	// value of option argument

int  getopt(int argc, char** argv, const char* options);

// getopt.h

struct option
{
    const char*  name;
    int	     has_arg;
    int*	     flag;
    int	     val;
        ...
};

int  getopt_long(int argc, char* const* argv, const char* shotops,
         const struct option* longopt, int* indexptr);

int getopt_long_only(int argc, char *const *argv, const char *shortopts,
             const struct option *longopts, int *indexptr);

// Пример реализации getopt для Windows из XGetOpt библиотеки

TCHAR	*optarg;	// global argument pointer
int	optind = 0; 	// global argv index

int getopt(int argc, TCHAR *argv[], TCHAR *optstring)
{
    static TCHAR *next = NULL;
    if (optind == 0)
        next = NULL;

    optarg = NULL;

    if (next == NULL || *next == _T('\0'))
    {
        if (optind == 0)
            optind++;

        if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0'))
        {
            optarg = NULL;
            if (optind < argc)
                optarg = argv[optind];
            return EOF;
        }

        if (_tcscmp(argv[optind], _T("--")) == 0)
        {
            optind++;
            optarg = NULL;
            if (optind < argc)
                optarg = argv[optind];
            return EOF;
        }

        next = argv[optind];
        next++;		// skip past -
        optind++;
    }

    TCHAR c = *next++;
    TCHAR *cp = _tcschr(optstring, c);

    if (cp == NULL || c == _T(':'))
        return _T('?');

    cp++;
    if (*cp == _T(':'))
    {
        if (*next != _T('\0'))
        {
            optarg = next;
            next = NULL;
        }
        else if (optind < argc)
        {
            optarg = argv[optind];
            optind++;
        }
        else
        {
            return _T('?');
        }
    }

    return c;
}

  Первичный разбор командной строки

При написании библиотек возникает еще задача - разобрать RAW строку
в argc/argv.

// Пример такой функции разборки для Windows:

#define _MAX_CMD_LINE_ARGS  128

char * _ppszArgv[_MAX_CMD_LINE_ARGS+1];

int __cdecl _ConvertCommandLineToArgcArgv( void )
{
    int cbCmdLine;
    int argc;
    PSTR pszSysCmdLine, pszCmdLine;

    // Set to no argv elements, in case we have to bail out
    _ppszArgv[0] = 0;

    // First get a pointer to the system's version of the command line, and
    // figure out how long it is.
    pszSysCmdLine = GetCommandLine();
    cbCmdLine = lstrlen( pszSysCmdLine );

    // Allocate memory to store a copy of the command line.  We'll modify
    // this copy, rather than the original command line.  Yes, this memory
    // currently doesn't explicitly get freed, but it goes away when the
    // process terminates.
    pszCmdLine = (PSTR)HeapAlloc( GetProcessHeap(), 0, cbCmdLine+1 );
    if ( !pszCmdLine )
        return 0;

    // Copy the system version of the command line into our copy
    lstrcpy( pszCmdLine, pszSysCmdLine );

    if ( '"' == *pszCmdLine )   // If command line starts with a quote ("),
    {                           // it's a quoted filename.  Skip to next quote.
        pszCmdLine++;

        _ppszArgv[0] = pszCmdLine;  // argv[0] == executable name

        while ( *pszCmdLine && (*pszCmdLine != '"') )
            pszCmdLine++;

        if ( *pszCmdLine )      // Did we see a non-NULL ending?
            *pszCmdLine++ = 0;  // Null terminate and advance to next char
        else
            return 0;           // Oops!  We didn't see the end quote
    }
    else    // A regular (non-quoted) filename
    {
        _ppszArgv[0] = pszCmdLine;  // argv[0] == executable name

        while ( *pszCmdLine && (' ' != *pszCmdLine) && ('\t' != *pszCmdLine) )
            pszCmdLine++;

        if ( *pszCmdLine )
            *pszCmdLine++ = 0;  // Null terminate and advance to next char
    }

    // Done processing argv[0] (i.e., the executable name).  Now do th
    // actual arguments

    argc = 1;

    while ( 1 )
    {
        // Skip over any whitespace
        while ( *pszCmdLine && (' ' == *pszCmdLine) || ('\t' == *pszCmdLine) )
            pszCmdLine++;

        if ( 0 == *pszCmdLine ) // End of command line???
            return argc;

        if ( '"' == *pszCmdLine )   // Argument starting with a quote???
        {
            pszCmdLine++;   // Advance past quote character

            _ppszArgv[ argc++ ] = pszCmdLine;
            _ppszArgv[ argc ] = 0;

            // Scan to end quote, or NULL terminator
            while ( *pszCmdLine && (*pszCmdLine != '"') )
                pszCmdLine++;

            if ( 0 == *pszCmdLine )
                return argc;

            if ( *pszCmdLine )
                *pszCmdLine++ = 0;  // Null terminate and advance to next char
        }
        else                        // Non-quoted argument
        {
            _ppszArgv[ argc++ ] = pszCmdLine;
            _ppszArgv[ argc ] = 0;

            // Skip till whitespace or NULL terminator
            while ( *pszCmdLine && (' '!=*pszCmdLine) && ('\t'!=*pszCmdLine) )
                pszCmdLine++;

            if ( 0 == *pszCmdLine )
                return argc;

            if ( *pszCmdLine )
                *pszCmdLine++ = 0;  // Null terminate and advance to next char
        }

        if ( argc >= (_MAX_CMD_LINE_ARGS) )
            return argc;
    }
}


81.5.1.2. ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

 Windows

LPTCH WINAPI GetEnvironmentStrings(void);
BOOL WINAPI FreeEnvironmentStrings(LPTCH lpszEnvironmentBlock);

DWORD WINAPI GetEnvironmentVariable(
  __in          LPCTSTR lpName,
  __out         LPTSTR lpBuffer,
  __in          DWORD nSize
);

BOOL WINAPI SetEnvironmentVariable(
  __in          LPCTSTR lpName,
  __in          LPCTSTR lpValue
);

DWORD WINAPI ExpandEnvironmentStrings(
  __in          LPCTSTR lpSrc,
  __out         LPTSTR lpDst,
  __in          DWORD nSize
);

    =C:=C:\Dir
    =D:=D:\Program Files

// stdlib.h

char*	getenv(const char* name)                                    // ISO
int	setenv(const char* name, const char* value, int overwrite) // POSIX
int	putenv(char* string)			// XSI
void	unsetenv(const char* name);		// POSIX
int	clearenv(void);

    putenv("PATH=/bin:/usr/bin");
    setenv("PATH", "/bin:/usr/bin");

extern char ** environ;

int main(int argc, char* argv[], char** envp)
{
}


81.5.1.3. HANDLES И HANDLE MANAGEMENT

THIS SECTION IS UNDER CONSTRUCTION

    delete handle on process closing

 Windows

BOOL WINAPI DuplicateHandle(
  __in          HANDLE hSourceProcessHandle,
  __in          HANDLE hSourceHandle,
  __in          HANDLE hTargetProcessHandle,
  __out         LPHANDLE lpTargetHandle,
  __in          DWORD dwDesiredAccess,
  __in          BOOL bInheritHandle,
  __in          DWORD dwOptions
);

BOOL WINAPI GetHandleInformation(
  __in          HANDLE hObject,
  __out         LPDWORD lpdwFlags
);

BOOL WINAPI SetHandleInformation(
  __in          HANDLE hObject,
  __in          DWORD dwMask,
  __in          DWORD dwFlags
);

    // dwFlags is:
    //	HANDLE_FLAG_INHERIT
    //	HANDLE_FLAG_PROTECT_FROM_CLOSE

    dup
    dup2
    fcntl


81.5.1.4. APC (APPLICATION SPECIFIC CALLBACKS)

THIS SECTION IS UNDER CONSTRUCTION

Сигналы

// POSIX

result = sigaction(int signalnum,
           const struct sigaction* action,
           struct sigaction* prevaction);

    struct sigaction
    {
        void (*sa_handler)();
        void (*sa_sigaction)(int, siginfo_t*, void*);
        sigset_t  sa_mask;
        int	  sa_flags;
                SA_RESETHAND
                SA_NODEFER
                SA_RESTART
                SA_SIGINFO

    };

// critical sections

// #include

int sigprocmask(int how, const sigset_t* sigs, sigset_t* prevsigs);
        SIG_BLOCK
        SIG_UNBLOCK
        SIG_SET

    sigemptyset(sigset_t*)
    sigfullset(sigset_t*)
    sigaddset(sigset_t*, int signum)
    sigdelset(sigset_t*, int signum)

int kill(pid_t pid, int signal)

    sigpending

ssize_t	ret;

while (len != 0 && (ret = read(fd, buf, len)) != 0)
{
    if (ret == -1)
    {
        if (errno == EINTR) continue;
        break;
    }
    len -= ret;
    buf += ret;
}

// signal.h
void* signal(int signum, void* handler);
        SIG_IGN         // ignore
        SIG_DFL		// default action

int   raise(int signum);

int   raise(int signum)
{
    return kill(getpid(), signum);
}

    SIGABRT
    SIGALRM
    SIGBUS
    SIGCHLD
    SIGCONT
    SIGFPE
    SIGHUP
    SIGILL
    SIGINT
    SIGIO
    SIGKILL
    SIGPIPE
    SIGPROF
    SIGPWR
    SIGQUIT
    SIGSEGV
    SIGSTOP
    SIGSYS
    SIGTERM
    SIGTRAP
    SIGTSTP
    SIGTTIN
    SIGTTOU
    SIGURG
    SIGUSR1
    SIGUSR2
    SIGVTALRM
    SIGWINCH
    SIGXCPU
    SIGXFSZ

// #define _GNU_SOURCE
// #include
char*	strsignal(int signum)

union sigval
{
    int	sival_int;
    void*	sival_ptr;
};

void* sigqueue(pid_t pid, int signum, const union sigval value);

    QueryUserAPC

 Windows

NTSTATUS  NTAPI NtQueueApcThread(IN HANDLE ThreadHandle,
            IN PUSER_APC_ROUTINE  ApcRoutine,
            IN PVOID FirstArg,	// QueryUserAPC() APC address
            IN PVOID SecondArg,	// QueryUserAPC() APC argument
            IN PVOID ThirdArg);

VOID NTAPI _NativeUserRoutine(PVOID First Arg, PVOID SecondArg, PVOID ThirdArg)
{
    ((PAPCFUNC) FirstArg, ( (DWORD) SecondArg);
}

NTSTATUS NtAlertThread(HANDLE ThreadHandle);
NTSTATUS NtTestAlert(VOID);


81.5.2. ПОТОКИ

THIS SECTION IS UNDER CONSTRUCTION

  Потоки

Права доступа для потока
    THREAD_TERMINATE
    THREAD_SUSPEND_RESUME
    THREAD_GET_CONTEXT
    THREAD_SET_CONTEXT
    THREAD_SET_INFORMATION
    THREAD_QUERY_INFORMATION
    THREAD_SET_THREAD_TOKEN
    THREAD_IMPERSONATE
    THREAD_DIRECT_IMPERSONATION

  Создание и жизнь нити

 Windows

HANDLE WINAPI CreateThread(
  __in          LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in          SIZE_T dwStackSize,
  __in          LPTHREAD_START_ROUTINE lpStartAddress,
  __in          LPVOID lpParameter,
  __in          DWORD dwCreationFlags,
  __out         LPDWORD lpThreadId
);

HANDLE WINAPI CreateRemoteThread(
  __in          HANDLE hProcess,
  __in          LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in          SIZE_T dwStackSize,
  __in          LPTHREAD_START_ROUTINE lpStartAddress,
  __in          LPVOID lpParameter,
  __in          DWORD dwCreationFlags,
  __out         LPDWORD lpThreadId
);

HANDLE WINAPI OpenThread(
  __in          DWORD dwDesiredAccess,
  __in          BOOL bInheritHandle,
  __in          DWORD dwThreadId
);

VOID WINAPI ExitThread(
  __in          DWORD dwExitCode
);

DWORD WINAPI ResumeThread(
  __in          HANDLE hThread
);

DWORD WINAPI SuspendThread(
  __in          HANDLE hThread
);

BOOL WINAPI TerminateThread(
  __in_out      HANDLE hThread,
  __in          DWORD dwExitCode
);

BOOL WINAPI GetExitCodeThread(
  __in          HANDLE hThread,
  __out         LPDWORD lpExitCode
);

BOOL WINAPI SwitchToThread(void);

 UNIX

int	pthread_create(pthread_t* thread,
            const pthread_attr_t* attr,
            void* (*start_routine)(void*),
            void* arg);

void	pthread_exit(void* value_ptr);

int	pthread_cancel(pthread_t thread);

int	pthread_setcancelstate(int state, int* oldstate);
        PTHREAD_CANCEL_ASYNCHRONOUS
        PTHREAD_CANCEL_DEFFERED
void	pthread_testcancel(void);

// QNX
int	pthread_abort(pthread_t thread);

  Аттрибуты pthreads

 UNIX

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);

int pthread_attr_setstack (pthread_attr_t *attr void *stackaddr size_t stacksize);
int pthread_attr_getstack (const pthread_attr_t * restrict attr void ** restrict stackaddr size_t * restrict stacksize);
int pthread_attr_setstacksize (pthread_attr_t *attr size_t stacksize);
int pthread_attr_getstacksize (const pthread_attr_t *attr size_t *stacksize);
int pthread_attr_setguardsize (pthread_attr_t *attr size_t guardsize);
int pthread_attr_getguardsize (const pthread_attr_t *attr size_t *guardsize);
int pthread_attr_setstackaddr (pthread_attr_t *attr void *stackaddr);
int pthread_attr_getstackaddr (const pthread_attr_t *attr void **stackaddr);

Pthread scope

    PTHREAD_SCOPE_SYSTEM
    PTHREAD_SCOPE_PROCESS

int	pthread_attr_setscope(pthread_attr_t* attr, int scope);
int	pthread_attr_getscope(const pthread_attr_t* attr, int* scope);

void	pthread_cleanup_push(void(*routine)(void*), void* arg);
void	pthread_clenup_pop(int execute);

  Join нитей

 UNIX

int pthread_attr_setdetachstate (pthread_attr_t *attr int detachstate);
int pthread_attr_getdetachstate (const pthread_attr_t *attr int *detachstate);

    PTHREAD_CREATE_JOINABLE
    PTHREAD_CREATE_DETACHED

int	pthread_join(pthread_t thread, void** value_ptr);
int	pthread_timedjoin(pthread_t thread, void** value_ptr,
             const struct timespec* abstime);	// QNX, no POSIX

int	pthread_detach(pthread_t thread);

  Идентификация и самоидентификация нитей

 Windows

HANDLE WINAPI GetCurrentThread(void);	// fake handle
                    // для реального надо вызвать
                    // DuplicateHandle

DWORD WINAPI GetCurrentThreadId(void);

DWORD WINAPI GetProcessIdOfThread(
  __in          HANDLE Thread
);

  Управление scheduling нити

Windows:

Thread			Process	Priority
priority	Idle	Below	Normal	Above	High	Realtime
TimeCrit	15	15	15	15	15	31
Highest		6	8	10	12	15	26
Above		5	7	9	11	14	25
Normal		4	6	8	10	13	24
Below		3	5	7	9	12	23
Lowest          2       4       6	8	10	22
Idle            1	1	1	1	1	16

 Windows

int WINAPI GetThreadPriority(
  __in          HANDLE hThread
);

BOOL WINAPI SetThreadPriority(
  __in          HANDLE hThread,
  __in          int nPriority
);

BOOL WINAPI GetThreadPriorityBoost(
  __in          HANDLE hThread,
  __out         PBOOL pDisablePriorityBoost
);

BOOL WINAPI SetThreadPriorityBoost(
  __in          HANDLE hThread,
  __in          BOOL DisablePriorityBoost
);

DWORD_PTR WINAPI SetThreadAffinityMask(
  __in          HANDLE hThread,
  __in          DWORD_PTR dwThreadAffinityMask
);

DWORD WINAPI SetThreadIdealProcessor(
  __in          HANDLE hThread,
  __in          DWORD dwIdealProcessor
);

DWORD WINAPI GetCurrentProcessorNumber(void);

 UNIX

// POSIX
int pthread_attr_setschedparam (pthread_attr_t *attr const struct sched_param *param);
int pthread_attr_getschedparam (const pthread_attr_t *attr struct sched_param *param);
int pthread_attr_setschedpolicy (pthread_attr_t *attr int policy);
int pthread_attr_getschedpolicy (const pthread_attr_t *attr int *policy);
int pthread_attr_setinheritsched (pthread_attr_t *attr int inheritsched);
int pthread_attr_getinheritsched (const pthread_attr_t *attr int *inheritsched);

    PTHREAD_EXPLICIT_SCHED

// Linux
int pthread_attr_setaffinity_np(pthread_attr_t attr,
                   size_t cpusetsize, const cpu_set_t *cpuset);
int pthread_attr_getaffinity_np(pthread_attr_t attr,
                   size_t cpusetsize, cpu_set_t *cpuset);

  Статистика

 Windows

BOOL WINAPI GetThreadTimes(
  __in          HANDLE hThread,
  __out         LPFILETIME lpCreationTime,
  __out         LPFILETIME lpExitTime,
  __out         LPFILETIME lpKernelTime,
  __out         LPFILETIME lpUserTime
);

    sched_yield()
        побочный эффект:
        sleep()
        delay()

Про:
    мьютексы
    семафоры
    критические секции
    барьеры
        и другие механизмы синхронизации
можно прочитать в секции 82.1.ПРИМИТИВЫ СИНХРОНИЗАЦИИ

  TLS

Thread specific data

 UNIX

int pthread_key_create (pthread_key_t *key void (*destructor)(void *));
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);

  Имперсонация нити

THIS SECTION IS UNDER CONSTRUCTION

 Windows

NTSTATUS NTAPI NtImpersonateThread(IN HANDLE ThreadHandle,
                   IN HANDLE TargetThreadHandle,
                   IN PSECURITY_QUALITY_OF_SERVICE SecurityQos);

NTSTATUS NTAPI NtImpersonateAnonymousToken(IN HANDLE ThreadHandle);

  Нотификация о завершении нити

 Windows

NTSTATUS NTAPI NtRegisterThreadTerminatePort(IN HANDLE PortHandle);

  Контекст нити

 Windows

BOOL WINAPI GetThreadContext(
  __in          HANDLE hThread,
  __in_out      LPCONTEXT lpContext
);

BOOL WINAPI SetThreadContext(
  __in          HANDLE hThread,
  __in          const CONTEXT* lpContext
);

typedef	struct	_CONTEXT
{
    DWORD	ContextFlags;
        // CONTEXT_FLOATING_POINT
    DWORD	Dr0;
    DWORD	Dr1;
    DWORD	Dr2;
    DWORD	Dr3;
    DWORD	Dr6;
    DWORD	Dr7;

    FLOATING_SAVE_AREA  FloatSave;
    DWORD	SegGs;
    DWORD	SegFs;
    DWORD	SegEs;
    DWORD	SegDs;

    DWORD	Edi;
    DWORD	Esi;
    DWORD	Ebx;
    DWORD	Edx;
    DWORD	Ecx;
    DWORD	Eax;

    DWORD	Ebp;
    DWORD	Eip;
    DWORD	SegCs;
    DWORD	EFlags;
    DWORD	Esp;
    DWORD	SegSs;

    BYTE	ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENTION];
};

  Стандартные библиотеки

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

    _beginthreadx
    _endthreadx

uintptr_t _beginthread(
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist
);

uintptr_t _beginthreadex(
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr
);

void _endthread( void );
void _endthreadex(unsigned retval);

Собственно для Windows стандартная библиотека имеет следущие per-theread
структуры:

struct _tiddata {
    unsigned long   _tid;       /* thread ID */

    uintptr_t _thandle;         /* thread handle */

    int     _terrno;            /* errno value */
    unsigned long   _tdoserrno; /* _doserrno value */
    unsigned int    _fpds;      /* Floating Point data segment */
    unsigned long   _holdrand;  /* rand() seed value */
    char *      _token;         /* ptr to strtok() token */
    wchar_t *   _wtoken;        /* ptr to wcstok() token */
    unsigned char * _mtoken;    /* ptr to _mbstok() token */

    /* following pointers get malloc'd at runtime */
    char *      _errmsg;        /* ptr to strerror()/_strerror() buff */
    wchar_t *   _werrmsg;       /* ptr to _wcserror()/__wcserror() buff */
    char *      _namebuf0;      /* ptr to tmpnam() buffer */
    wchar_t *   _wnamebuf0;     /* ptr to _wtmpnam() buffer */
    char *      _namebuf1;      /* ptr to tmpfile() buffer */
    wchar_t *   _wnamebuf1;     /* ptr to _wtmpfile() buffer */
    char *      _asctimebuf;    /* ptr to asctime() buffer */
    wchar_t *   _wasctimebuf;   /* ptr to _wasctime() buffer */
    void *      _gmtimebuf;     /* ptr to gmtime() structure */
    char *      _cvtbuf;        /* ptr to ecvt()/fcvt buffer */
    unsigned char _con_ch_buf[MB_LEN_MAX];
                                /* ptr to putch() buffer */
    unsigned short _ch_buf_used;   /* if the _con_ch_buf is used */

    /* following fields are needed by _beginthread code */
    void *      _initaddr;      /* initial user thread address */
    void *      _initarg;       /* initial user thread argument */

    /* following three fields are needed to support signal handling and
     * runtime errors */
    void *      _pxcptacttab;   /* ptr to exception-action table */
    void *      _tpxcptinfoptrs; /* ptr to exception info pointers */
    int         _tfpecode;      /* float point exception code */

    /* pointer to the copy of the multibyte character information used by
     * the thread */
    pthreadmbcinfo  ptmbcinfo;

    /* pointer to the copy of the locale informaton used by the thead */
    pthreadlocinfo  ptlocinfo;
    int         _ownlocale;     /* if 1, this thread owns its own locale */

    /* following field is needed by NLG routines */
    unsigned long   _NLG_dwCode;

    /*
     * Per-Thread data needed by C++ Exception Handling
     */
    void *      _terminate;     /* terminate() routine */
    void *      _unexpected;    /* unexpected() routine */
    void *      _translator;    /* S.E. translator */
    void *      _purecall;      /* called when pure virtual happens */
    void *      _curexception;  /* current exception */
    void *      _curcontext;    /* current exception context */
    int         _ProcessingThrow; /* for uncaught_exception */
    void *              _curexcspec;    /* for handling exceptions thrown from std::unexpected */
#if defined (_M_IA64) || defined (_M_AMD64)
    void *      _pExitContext;
    void *      _pUnwindContext;
    void *      _pFrameInfoChain;
    unsigned __int64    _ImageBase;
#if defined (_M_IA64)
    unsigned __int64    _TargetGp;
#endif  /* defined (_M_IA64) */
    unsigned __int64    _ThrowImageBase;
    void *      _pForeignException;
#elif defined (_M_IX86)
    void *      _pFrameInfoChain;
#endif  /* defined (_M_IX86) */
    _setloc_struct _setloc_data;

#ifdef _M_IX86
    void *      _encode_ptr;    /* EncodePointer() routine */
    void *      _decode_ptr;    /* DecodePointer() routine */
#endif  /* _M_IX86 */

    void *      _reserved1;     /* nothing */
    void *      _reserved2;     /* nothing */
    void *      _reserved3;     /* nothing */

    int _cxxReThrow;        /* Set to True if it's a rethrown C++ Exception */

    unsigned long __initDomain;     /* initial domain used by _beginthread[ex] for managed function */
};
typedef struct _tiddata * _ptiddata;

  Борьба с Livelocks

    Vista:
    OpenThreadWaitChainSesssion
    CloseThreadWaitChainSession
    GetThreadWaitChain

HWCT WINAPI OpenThreadWaitChainSession(
  __in          DWORD Flags,
  __in_opt      PWAITCHAINCALLBACK callback
);

VOID WINAPI CloseThreadWaitChainSession(
  __in          HWCT WctHandle
);

BOOL WINAPI GetThreadWaitChain(
  __in          HWCT WctHandle,
  __in_opt      DWORD_PTR Context,
  __in          DWORD Flags,
  __in          DWORD ThreadId,
  __in_out      LPDWORD NodeCount,
  __out         PWAITCHAIN_NODE_INFO NodeInfoArray,
  __out         LPBOOL IsCycle
);

VOID CALLBACK WaitChainCallback(
  HWCT WctHandle,
  DWORD_PTR Context,
  DWORD CallbackStatus,
  LPDWORD NodeCount,
  PWAITCHAIN_NODE_INFO NodeInfoArray,
  LPBOOL IsCycle
);


81.5.2.1. ПУЛЫ ПОТОКОВ

THIS SECTION IS UNDER CONSTRUCTION

Что такое пул потоков?

Несколько рабочих потоков ждут поступление заданий
Когда задание есть один поток его выполняет
Если потоков нет то либо запускают новый либо ставят
задачу в очередь

Создать
    min thread
    max thread

Поместить задачу в пул потоков  (Post task)
Узнать статус завершения задачи (Wait task)

BOOL TrySubmitThreadpoolCallback(
    PTP_SIMPLE_CALLBACK  pfnCallback,
    PVOID pvContext,
    PTP_CALLBACK_ENVIRON pcbd);

void NTAPI SimpleCallback(
    PTP_CALLBACK_INSTANCE pInstance,
    PVOID pvContext);

PTR_CALLBACK_ENVIRON
    NULL - используем pool по умолчанию
           (каждый процесс имеет свой pool)

PTP_POOL CreateThreadpool(PVOID reserved);
BOOL	 SetThreadpoolThreadMinimum(PTP_POOL pThreadPool, DWORD cthrdMin);
BOOL	 SetThreadpoolThreadMaximum(PTP_POOL pThreadPool, DWORD cthrdMost);

VOID	 CloseThreadpool(PTP_POOL pThreadPool);

VOID	 InitializeThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe);
VOID	 DestroyThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe);
VOID	 SetThreadpoolCallbackPool(PTP_CALLBACK_ENVIRON pcbe, PTP_POOL pThreadPool);

SetThreadpoolCallbacksRunsLong
SetThreadpoolCallbacksLibrary

CreateThreadpoolCleanupGroup
SetThreadpoolCleanupGroup
CloseThreadpoolCleanupGroupMembers
CloseThreadppolCleanupGroup

  work

PTR_WORK CreateThreadpoolWork(
    PTR_WORK_CALLBACK pfnWorkHandler,
    PVOID pvContext,
    PTP_CALLBACK_ENVIRON pcbe);

CreateThreadpoolWork		// создает Workitem вручную
Его можно ставить самостоятельно в очередь причем несколько раз
VOID SubmitThreadpoolWork(PTP_WORK pWork)

VOID WaitForThreadpoolWorkCallbacks(
    PTP_WORK pWork,
    BOOL  bCancelPendingCallbacks);

VOID CloseThreadpoolWork(PTR_WORK  pWork);

  timer

CreateThreadpoolTimer		// для переодической задачи
SetThreadpoolTimer

PTP_TIMER CreateThreadpoolTimer(
        PTP_TIMER_CALLBACK pInstance,
        PVOID pvContext,
        PTP_TIMER pTimer);

VOID SetThreadpoolTimer(
        PTP_TIMER	pTimer,
        PFILETIME	pfnDueTime,
        DWORD		msPeriod,
        DWORD		msWindowLength);

BOOL IsThreadpoolTimerSet(PTP_TIMER pt);

  wait

Вызов workitem по освобождению объектов ядра
CreateThreadpoolWait
SetThreadpoolWait
WaitForThreadpoolWaitCallbacks

PTP_WAIT CreateThreadpoolWait(
        PTP_WAIT_CALLBACK  pfnWaitCallback,
        PVOID		   pvContext,
        PTP_CALLBACK_ENVIRON  pcbe);

VOID	SetThreadpoolWait(
        PTP_WAIT	pWaitItem,
        HANDLE		hObject
        PFILETIME	pftTimeOut);

  io

Вызов workitem по завершению асинхронной операции ввода/вывода
CreateThreadpoolIo

PTP_IO  CreateThreadpoolIo(
        HANDLE		hDevice,
        PTP_WIN32_IO_CALLBACK  pfnIoCallback,
        PVOID		pvContext,
        PTP_CALLBACK_ENVIRON  pcbe);

VOID	StartThreadpoolIo(PTP_IO pio);
VOID	CancelThreadpoolIo(PTP_IO pio);
VOID	CloseThreadpoolIo(PTP_IO pio);
VOID	WaitForThreadpoolIoCallbacks(
            PTP_IO  pio,
            BOOL    bCancelPendignCallbacks);

    CreateThreadPoolWork	etc
        async
        by timer
        on release objects
        on compete I/O

  I/O completion port

I/O completion port - объект синхронизации который оповещает паралельно
работающие потоки о завершении асинхронных операций ввода/вывода к файлам
и каналам.

Подключение файлов к порту
    Каждый файл имеет свой сompletion key

При завершении операции ввода/вывода система посылает пакет в порт
В порте очередь пакетов (FIFO)

Очередь потоков в порте (LIFO)

 Windows

HANDLE 	CreateIoCompletionPort(HANDLE hFile,
                   HANDLE hExistingIoCompletionPort,
                   ULONG* ulCompletionKey,
                   DWORD  dwNumberOfConcurrentThreads);

BOOL	PostQueuedCompletionStatus(HANDLE hCompletionPort,
                WORD  lpNumberOfBytesTransffered,
                ULONG* ulCompletionKey,
                LPOVERLAPPED* lpOverlappped);

BOOL	GetQueuedCompletionStatus(HANDLE  hCompletionPort,
                LPDWORD  lpNumberOfBytes,
                ULONG*   ulCompletionKey,
                LPOVERLAPPED* lpOverlapped,
                DWORD  dwMilliseconds);

Создание нового completion port

    CreateIoCompletionPort(INVALID_HANDLE_VALUE,
                   NULL,
                   0,
                   dwNumberOfConcurrentThreads);

Связование файла с портом завершения

    CreateIoCompletionPort(hDevice,
                   hCompletionPort,
                   dwCompletionKey,
                   0);

 Windows

NTSTATUS NTAPI NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle,
            IN ACCESS_MASK  DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes,
            IN ULONG NumberOfConcurrentThreads);

NTSTATUS NTAPI NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle,
            IN ACCESS_MASK  DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes);

NTSTATUS NTAPI NtSetIoCompletion(IN HANDLE IoCompletionHandle,
            IN ULONG CompletionKey,
            IN ULONG CompletionValue,
            IN NTSTATUS Status,
            IN ULOMG Information);

NTSTATUS NTAPI NtRemoveIoCompletion(IN HANDLE IoCompletionHandle,
            OUT PULONG CompletionKey,
            OUT PULONG CompletionValue,
            OUT PIO_STATUS_BLOCK IoStatusBlock,
            IN PLARGE_INTEGER Timeout OPTIONAL);


81.5.2.2. ВОЛОКНА

  Волокна

 Windows

LPVOID WINAPI CreateFiber(
  __in          SIZE_T dwStackSize,
  __in          LPFIBER_START_ROUTINE lpStartAddress,
  __in          LPVOID lpParameter);

LPVOID WINAPI ConvertThreadToFiber(
  __in          LPVOID lpParameter);

VOID WINAPI DeleteFiber(
  __in          LPVOID lpFiber);

PVOID GetCurrentFiber(void);

PVOID GetFiberData(void);

VOID WINAPI SwitchToFiber(LPVOID lpFiber);


81.5.3. IPC

THIS SECTION IS UNDER CONSTRUCTION

IPC (Interprocess Communication)

Два основных типа взаимодействия.

1) Сообщения

2) Разделяемая память

Про примитивы синхронизации такие как
    мьютекс
    семафор
    event
        итд
можно прочитать в секции 82.1.ПРИМИТИВЫ СИНХРОНИЗАЦИИ

  Messages

  pipes

// unistd.h
int	pipe(int  fds[2]);

FILE* popen(const char* cmd, const char* mode);
int   pclose(FILE* stream);

BOOL WINAPI CreatePipe(
  __out         PHANDLE hReadPipe,
  __out         PHANDLE hWritePipe,
  __in          LPSECURITY_ATTRIBUTES lpPipeAttributes,
  __in          DWORD nSize
);

  Named pipes

HANDLE WINAPI CreateNamedPipe(
  __in          LPCTSTR lpName,
  __in          DWORD dwOpenMode,
  __in          DWORD dwPipeMode,
  __in          DWORD nMaxInstances,
  __in          DWORD nOutBufferSize,
  __in          DWORD nInBufferSize,
  __in          DWORD nDefaultTimeOut,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

BOOL WINAPI ConnectNamedPipe(
  __in          HANDLE hNamedPipe,
  __in          LPOVERLAPPED lpOverlapped
);

BOOL WINAPI DisconnectNamedPipe(
  __in          HANDLE hNamedPipe
);

BOOL WINAPI WaitNamedPipe(
  __in          LPCTSTR lpNamedPipeName,
  __in          DWORD nTimeOut
);

BOOL WINAPI PeekNamedPipe(
  __in          HANDLE hNamedPipe,
  __out         LPVOID lpBuffer,
  __in          DWORD nBufferSize,
  __out         LPDWORD lpBytesRead,
  __out         LPDWORD lpTotalBytesAvail,
  __out         LPDWORD lpBytesLeftThisMessage
);

BOOL WINAPI CallNamedPipe(
  __in          LPCTSTR lpNamedPipeName,
  __in          LPVOID lpInBuffer,
  __in          DWORD nInBufferSize,
  __out         LPVOID lpOutBuffer,
  __in          DWORD nOutBufferSize,
  __out         LPDWORD lpBytesRead,
  __in          DWORD nTimeOut
);

BOOL WINAPI TransactNamedPipe(
  __in          HANDLE hNamedPipe,
  __in          LPVOID lpInBuffer,
  __in          DWORD nInBufferSize,
  __out         LPVOID lpOutBuffer,
  __in          DWORD nOutBufferSize,
  __out         LPDWORD lpBytesRead,
  __in          LPOVERLAPPED lpOverlapped
);

BOOL WINAPI GetNamedPipeHandleState(
  __in          HANDLE hNamedPipe,
  __out         LPDWORD lpState,
  __out         LPDWORD lpCurInstances,
  __out         LPDWORD lpMaxCollectionCount,
  __out         LPDWORD lpCollectDataTimeout,
  __out         LPTSTR lpUserName,
  __in          DWORD nMaxUserNameSize
);

BOOL WINAPI SetNamedPipeHandleState(
  __in          HANDLE hNamedPipe,
  __in          LPDWORD lpMode,
  __in          LPDWORD lpMaxCollectionCount,
  __in          LPDWORD lpCollectDataTimeout
);

BOOL WINAPI GetNamedPipeClientProcessId(
  __in          HANDLE Pipe,
  __out         PULONG ClientProcessId
);

BOOL WINAPI GetNamedPipeClientSessionId(
  __in          HANDLE Pipe,
  __out         PULONG ClientSessionId
);

BOOL WINAPI GetNamedPipeServerProcessId(
  __in          HANDLE Pipe,
  __out         PULONG ServerProcessId
);

BOOL WINAPI GetNamedPipeServerSessionId(
  __in          HANDLE Pipe,
  __out         PULONG ServerSessionId
);

BOOL WINAPI GetNamedPipeInfo(
  __in          HANDLE hNamedPipe,
  __out         LPDWORD lpFlags,
  __out         LPDWORD lpOutBufferSize,
  __out         LPDWORD lpInBufferSize,
  __out         LPDWORD lpMaxInstances
);

    CreateNamedPipe
    ConnectNamedPipe
    DisconnectNamedPipe
    WaitNamedPipe
    PeekNamedPipe
    TransactNamedPipe
    CallNamedPipe
    GetNamedPipeHandleState
    SetNamedPipeHandleState
    GetNamedPipeInfo

  Mailslotes

    CreateMailslot
    GetMailslotInfo
    SetMailslotInfo

HANDLE WINAPI CreateMailslot(
  __in          LPCTSTR lpName,
  __in          DWORD nMaxMessageSize,
  __in          DWORD lReadTimeout,
  __in_opt      LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

BOOL WINAPI GetMailslotInfo(
  __in          HANDLE hMailslot,
  __out         LPDWORD lpMaxMessageSize,
  __out_opt     LPDWORD lpNextSize,
  __out_opt     LPDWORD lpMessageCount,
  __out_opt     LPDWORD lpReadTimeout
);

BOOL WINAPI SetMailslotInfo(
  __in          HANDLE hMailslot,
  __in          DWORD lReadTimeout
);

  UNIX domain Sockets

UNIX domain sockets

int socket(int domain, int type, int protocol)

// sys/socket.h
// sys/un.h

struct sockaddr_un
{
    unsigned short sun_family;		AF_UNIX
    char	       sun_path[UNIX_PATH_MAX=108];
};

bind
connect
accept

int socketpair(int domain, int type, int protocol, int sockfd[2]);

int sendmsg(int fd, const struct msghdr* msg, unsigned int flags);
int recvmsg(int fd, stcut msghdr* msg, unsigned int flags);

struct msghdr
{
    void*	msg_name;
    unsigned int msg_namelen;
    struct iovec* msg_iov;
    unsigned int msg_iovlen;
    void* msg_control;
    unsigned int msg_controllen;
    int msg_flags;
}

  Messages

Message queue

  LPC

 Windows

NTSTATUS NTAPI NtCreatePort(OUT PHANDLE PortHandle,
        IN POBJECT_ATTRIBUTES ObjectAttributes,
        IN DWORD  MaxDataSize,
        IN DWORD  MaxMessageSize,
        IN DWORD  Reserved);

//	MaxDataSize    <= 0x104
//	MaxMessageSize <= 0x148

NTSTATUS NTAPI NtCreateWaitablePort(OUT PHANDLE PortHandle,
        IN POBJECT_ATTRIBUTES ObjectAttributes,
        IN DWORD  MaxDataSize,
        IN DWORD  MaxMessageSize,
        IN DWORD  Reserved);

NTSTATUS NTAPI NtConnectPort(
        OUT PHANDLE PortHandle,
        IN  PUNICODE_STRING PortName,
        IN  PSECURITY_QUALITY_OF_SERVICE SequrityQos,
        IN OUT  PPORT_SECTION_WRITE WriteSection OPTIONAL,
        IN OUT  PPORT_SECTION_READ  ReadSection OPTIONAL,
        OUT PULONG MaxMessageSize OPTIONAL,
        IN OUT PVOID  ConnectData OPTIONAL,
        IN OUT PULONG ConnectDataLength OPTIONAL);

NTSTATUS NTAPI NtSecureConnectPort(
        OUT PHANDLE PortHandle,
        IN  PUNICODE_STRING PortName,
        IN  PSECURITY_QUALITY_OF_SERVICE SequrityQos,
        IN OUT  PPORT_SECTION_WRITE WriteSection OPTIONAL,
        IN PSID ServerSid OPTIONAL,
        IN OUT  PPORT_SECTION_READ  ReadSection OPTIONAL,
        OUT PULONG MaxMessageSize OPTIONAL,
        IN OUT PVOID  ConnectData OPTIONAL,
        IN OUT PULONG ConnectDataLength OPTIONAL);

NTSTATUS  NTAPI NtListenPort(
        IN HANDLE PortHandle,
        OUT PPORT_MESSAGE  pLpcMessage);

NTSTATUS NTAPI  NtAcceptConnectPort(
            OUT PHANDLE  PortHandle,
            IN  ULONG  PortIdentifier,
            IN  PPORT_MESSAGE  LpcMessage,
            IN  BOOLEAN   AcceptIt,
            IN OUT PPORT_SECTION_WRITE  WriteSection OPTIONAL,
            IN OUT PPORT_SECTION_READ   ReadSection OPTIONAL);

NTSTATUS NTAPI NtCompleteConnectPort(HANDLE PortHandle);

NTSTATUS  NTAPI NtRequestPort(
            IN HANDLE PortHandle,
            IN PPORT_MESSAGE  pLpcMessage);

NTSTATUS  NTAPI NtReplyPort(
            IN HANDLE PortHandle,
            IN PPORT_MESSAGE  pLpcMessage);

NTSTATUS NTAPI  NtRequestWaitReplyPort(
            IN HANDLE PortHandle,
            IN PPORT_MESSAGE  pLpcMessageIn,      // Request message
            OUT PPORT_MESSAGE pLpcOutMessageOut); // Reply message

NTSTATUS NTAPI  NtReplyWaitReplyPort(
            IN HANDLE PortHandle,
            IN OUT PPORT_MESSAGE ReplyMessage);

NTSTATUS NTAPI  NtReplyWaitReceivePort(
            IN HANDLE PortHandle,
            OUT PULONG PortIdentifier OPTIONAL,
            IN PPORT_MESSAGE ReplyMessage OPTIONAL,
            OUT PPORT_MESSAGE Message);

NTSTATUS NTAPI  NtReplyWaitReceivePortEx(
            IN HANDLE PortHandle,
            OUT PULONG PortIdentifier OPTIONAL,
            IN PPORT_MESSAGE ReplyMessage OPTIONAL,
            OUT PPORT_MESSAGE Message,
            IN PLARGE_INTEGER TimeOut);

NTSTATUS NTAPI  NtReadRequestData(
            IN HANDLE  PortHandle,
            IN PPORT_MESSAGE Message,
            IN ULONG   Index,
            OUT PVOID  Buffer,
            IN ULONG   BufferLength,
            OUT PULONG ReturnLength OPTIONAL);

NTSTATUS NTAPI  NtWriteRequestData(
            IN HANDLE  PortHandle,
            IN PPORT_MESSAGE Message,
            IN ULONG   Index,
            IN PVOID  Buffer,
            IN ULONG   BufferLength,
            OUT PULONG ReturnLength OPTIONAL);

NTSTATUS  NTAPI NtImpersonateClientOfPort(HANDLE PortHandle,
                      PPORT_MESSAGE pLpcMessage);

    typedef struct _PORT_MESSAGE
    {
        USHORT	DataSize;
        USHORT	MessageSize;
        USHORT	MessageType;
        CLIENT_ID	ClientId;	// process id, thread id
        ULONG	MessageId;
        ULONG	SectionSize;		// shared section size
        BYTE	Data[];			// [MAX_MESSAGE_SIZE]
    } PORT_MESSAGE, * PPORT_MESSAGE;

    typedef enum _LPC_TYPE
    {
        LPC_NEW_MESSAGE,
        LPC_REQUEST,
        LPC_REPLY,
        LPC_DATAGRAM,
        LPC_LOST_REPLY,
        LPC_PORT_CLOSED,
        LPC_CLIENT_DIED,
        LPC_EXCEPTION,
        LPC_DEBUG_EVENT,
        LPC_ERROR_EVENT,
        LPC_CONNECTION_REQUEST
    } LPC_TYPE;

    typedef struct _PORT_SECTION_WRITE
    {
        ULONG	Length;
        HANDLE	SectionHandle;
        ULONG	SectionOffset;
        ULONG	ViewSize;
        PVOID	ViewBase;
        PVOID	TargetViewBase;
    } PORT_SECTION_WRITE, * PPORT_SECTION_WRITE;

    typedef struct _PORT_SECTION_READ
    {
        ULONG	Length;
        ULONG	ViewSize;
        ULONG	ViewBase;
    } PORT_SECTION_READ, * PPORT_SECTION_READ;

NTSTATUS  NTAPI NtRegisterThreadTerminatePort(HANDLE PortHandle);

NTSTATUS  NTAPI NtSetDefaultHardErrorPort(HANDLE PortHandle)

  RPC

Асинхронный RPC

Deffered synchronous RPC

RPC Binding

RpcServerUseProtseqEp
RpcServerUseProtseqIf
RpcServerUseProtseq

RpcServerRegisterIf

RpcServerInqBinding
RpcNsBindingExport

RpcServerListen

RpcStringBindingCompose

RpcBindingImportBegin
RpcNsBindingImportNext
RpcNsBindingImportDone

RpcExcept

  Clipboard

  Shared Memory


81.5.4. ОТЛАДКА

THIS SECTION IS UNDER CONSTRUCTION

    Интерфейсы для отладки приложений

CreateProcess()		with special flag
DebugActiveProcess()

WaitForDebugEvent

Breakpoints:
    ReadProcessMemory
    WriteProcessMemory

    user breakpoint
    single step
    run-to-there
    finish function
    function evaluation
    messagepoint
    profiling

ptrace
   Linux
    PTRACE_ATTACH
    PTRACE_CONT
    PTRACE_DETACH
    PTRACE_GET_THREAD_AREA
    PTRACE_GETEVENTMSG
    PTRACE_GETFPREGS
    PTRACE_GETFPXREGS
    PTRACE_GETREGS
    PTRACE_GETSIGINFO
    PTRACE_KILL
    PTRACE_OLDSETOPTIONS
    PTRACE_PEEKDATA
    PTRACE_PEEKTEXT
    PTRACE_PEEKUSR
    PTRACE_POKEDATA
    PTRACE_POKETEXT
    PTRACE_POKEUSR
    PTRACE_SET_THREAD_AREA
    PTRACE_SETFPREGS
    PTRACE_SETFPXREGS
    PTRACE_SETREGS
    PTRACE_SETOPTIONS
    PTRACE_SETSIGINFO
    PTRACE_SINGLESTEP
    PTRACE_SYSCALL
    PTRACE_TRACEME


81.5.5. ФОРМАТЫ ИСПОЛНЯЕМЫХ ФАЙЛОВ

THIS SECTION IS UNDER CONSTRUCTION

COM
EXE
a.out
PE
ELF


81.5.6. ОПРЕДЕЛЕНИЕ ВЕРСИИ ОПЕРАЦИОННОЙ СИСТЕМЫ

THIS SECTION IS UNDER CONSTRUCTION


81.5.7. СТАНДАРТНЫЕ БИБЛИОТЕКИ

// Новый стандарт для C++

namespace std
{
    class thread;

    void swap(thread& x, thread& y);

    namespace this_thread
    {
        thread::id get_id();
        void yield();
        template
            void sleep_until(const chrono::time_point& abs_time);
        template
            void sleep_for(const chrono::duration& rel_time);
    }

    class thread
    {
    public:
        class id;
        typedef implementation-defined native_handle_type;

    thread();
    template  explicit thread(F f);
    template  thread(F&& f, Args&&... args);
    ~thread();
    thread(const thread&) = delete;
    thread(thread&&);
    thread& operator=(const thread&) = delete;
    thread& operator=(thread&&);

    void swap(thread&);
    bool joinable() const;
    void join();
    void detach();
    id get_id() const;
    native_handle_type native_handle(); // See 30.2.3

    static unsigned hardware_concurrency();
    };

    class thread::id
    {
    public:
        id();
    };

    bool operator==(thread::id x, thread::id y);
    bool operator!=(thread::id x, thread::id y);
    bool operator<(thread::id x, thread::id y);
    bool operator<=(thread::id x, thread::id y);
    bool operator>(thread::id x, thread::id y);
    bool operator>=(thread::id x, thread::id y);
    template
        basic_ostream&
            operator<< (basic_ostream& out, thread::id id);
}


81.6. ЗАДАЧИ ПОДИСТЕМА БЕЗОПАСНОСТИ

Главное - это контроль и разграничение доступа.

    Ауфентикация -
    Авторизация  -
    Имперсонация -
    Аудит -


81.6.1. ACL (ACCESS CONTROL LISTS)

Имеем огромную трехмерную матрицу безопасности в системе.
1я координата - Субъекты
2я координата - Объекты
3я координата - Методы

Таким образом защита описывает доступ Субъекта к Объекта методом.

Следущий уровень:
Субъект в субъекте - Группа

Субъект в объекте - Владелец

Субъект в методе - Root - может иметь доступ ко всему
Объект в субъекте - Principal Parent Owner
Объект в объекте - Наследование прав доступа
Объект в методе - Аудит
Метод в субъекте - Ограниченные привелегии (Restricted user account) (не по умолчанию, а только при явном указании что разрешено)
Метод в объекте  - Специальные типы файлов (например нестираемые, или только для добавления)
Метод в методе -  Generic Read/Generic Write etc

ACL (Access Control Lists)

  Типовые методы

 ------------------------------------------------------------------
Тип Объекта		Метод			Метод в объекте
 ------------------------------------------------------------------
File			Read File  		Append only file
            Write File		Rename inhibit
            Append File		Delete inhibit
            Read Attributes         Truncate inhibit
            Write Attributes
            Read EA
            Write EA
            Delete
 ------------------------------------------------------------------
Directory		List directory		sticky
            Add file
            Add subdirectory
            Traverse
            Delete child
            Read Attributes
            Write Attributes
            Read EA
            Write EA
 ------------------------------------------------------------------

  Упаковка ACL

Полный список доступа

USER1: ALLOW(R), DENY(WD)
USER2: ALLOW(), DENY(RWD)
GROUP1: ALLOW(W), DENY(RD)
GROUP2: ALLOW(RWD), DENY()

Полный список доступа (по умолчанию доступ разрешен)

// DEFAULT=ALLOW
USER1: WD
USER2: RWD
GROUP1: RD

Цель: минимизация размера ACL

Полный список доступа (по умолчанию доступ разрешен)

// DEFAULT=DENY
USER1: R
GROUP1: W
GROUP2: RWD

  Наследование ACL

Родительский список доступа

// DEFAULT = DENY
USER1: R
GROUP1: W
GROUP2: R

Дочерний список доступа

// DEFAULT = DENY
// INHERIT FROM PARENT
GROUP2: WD

Цель: Минимизация размера ACL

  UNIX permisions


81.6.1.1. SECURITY ID

THIS SECTION IS UNDER CONSTRUCTION


81.6.2. АУФЕНТИКАЦИЯ

THIS SECTION IS UNDER CONSTRUCTION

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

Методы:
    - Знание ключа
        пароля в случае пользователя
    - Владение ключевой информацией
        Smart cards
        карточки доступа
    - Биометрия


81.6.2.1. БИОМЕТРИЯ

THIS SECTION IS UNDER CONSTRUCTION

  Отпечаток пальца

  Keystroke dynamics

  Сканнер глаза

Сканирование сосудов дна

  Face recognition

  Voice recognition

THIS SECTION IS UNDER CONSTRUCTION

  DNA recognition

Пример распознование ДНК на примере жертвы сексуального инцидента.

На самом деле биометрических методов сотни.


81.6.3. ИМПЕРСОНАЦИЯ

THIS SECTION IS UNDER CONSTRUCTION

Имперсонация -

    запуск программ из под другово пользователя, как правило администратора
        suid
        sgid
        UAC

    выполнение кода под аккаунтом другово пользователя
        RPC


81.6.4. АУДИТ

THIS SECTION IS UNDER CONSTRUCTION


81.6.5. ПРИВИЛЕГИИ

THIS SECTION IS UNDER CONSTRUCTION

    Привилегии

    Restricted Token
    UAC

Windows:

Priveleges

    SeAssignPrimaryTokenPrivilege
    SeAuditPrivilege
    SeBackupPrivilege
    SeChangeNotifyPrivilege
    SeCreatePagefilePrivilege
    SeCreatePermanentPrivilege
    SeCreateTokenPrivilege
    SeDebugPrivilege
    SeEnableDelegationPrivilege
    SeIncreaseBasePriorityPrivilege
    SeIncreaseQuotaPrivilege
    SeLoadDriverPrivilege
    SeLockMemoryPrivilege
    SeMachineAccountPrivilege
    SeProfileSingleProcessPrivilege
    SeRemoteShutdownPrivilege
    SeRestorePrivilege
    SeSecurityPrivilege
    SeShutdownPrivilege
    SeSyncAgentPrivilege
    SeSystemEnvironmentPrivilege
    SeSystemProfilePrivilege
    SeSystemtimePrivilege
    SeTakeOwnershipPrivilege
    SeTcbPrivilege
    SeUndockPrivilege
    SeUnsolicitedInputPrivilege

TODO: дописать остальные привилегии

    SeBatchLogonRight
    SeDenyInteractiveLogonRight
    SeDenyNetworkLogonRight
    SeDenyServiceLogonRight
    SeInteractiveLogonRight
    SeNetworkLogonRight
    SeServiceLogonRight

Linux:

POSIX 1003.1e process abilities

 UNIX

// sys/capability.h

int capget(cap_user_header_t header, cap_user_data_t data);
int capset(cap_user_header_t header, const cap_user_data_t data);

Linux capabilities

    CAP_AUDIT_WRITE
    CAP_AUDIT_CONTROL
    CAP_CHOWN
    CAP_DAC_OVERWRITE
    CAP_DAC_READ_SEARCH
    CAP_FOWNER
    CAP_FSETID
    CAP_KILL
    CAP_LINUX_IMMUTABLE
    CAP_IPC_LOCK
    CAP_IPC_OWNER
    CAP_LEASE
    CAP_MKNOD
    CAP_NET_ADMIN
    CAP_NET_BIND_SERVICE
    CAP_NET_BROADCAST
    CAP_NET_RAW
    CAP_SETGID
    CAP_SETPCAP
    CAP_SETUID
    CAP_SYS_ADMIN
    CAP_SYS_CHROOT
    CAP_SYS_MODULE
    CAP_SYS_NICE
    CAP_SYS_PACCT
    CAP_SYS_PTRACE
    CAP_SYS_RAWIO
    CAP_SYS_RESOURCE
    CAP_SYS_TIME
    CAP_SYS_TTY_CONFIG

    capget
    capset


81.6.6. ACCOUNT MANAGEMENT

THIS SECTION IS UNDER CONSTRUCTION

    Пользователи
        Создание
        Блокирование
        Удаление
        Свойства

    Группы
        Создание
        Удаление
        Добавление в группу
        Удаление из группы
        Свойства

UNIX:

 UNIX

// pwd.h

struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);

int getpwnam_r(const char *name, struct passwd *pwd,
              char *buf, size_t buflen, struct passwd **result);
int getpwuid_r(uid_t uid, struct passwd *pwd,
              char *buf, size_t buflen, struct passwd **result);

struct passwd
{
    char   *pw_name;       /* username */
    char   *pw_passwd;     /* user password */
    uid_t   pw_uid;        /* user ID */
    gid_t   pw_gid;        /* group ID */
    char   *pw_gecos;      /* real name */
    char   *pw_dir;        /* home directory */
    char   *pw_shell;      /* shell program */
};

struct passwd *getpwent(void);	// интерфейс для энумерации
void 	      setpwent(void);	//- в начало файла
void          endpwent(void);

// grp.h

struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);

struct group
{
        char    *gr_name;        /* название группы */
        char    *gr_passwd;      /* пароль группы */
        gid_t   gr_gid;          /* идентификатор группы */
        char    **gr_mem;        /* члены группы */
};

struct group* getgrent(void);
void 	      setgrent(void);
void 	      endgrent(void);

Windows:

    NetApiBufferFree

    NetUserAdd
    NetUserGetInfo
    NetUserSetInfo
    NetUserEnum
    NetUserDel
    NetUserGetLocalGroups
    NetUserChangePassword

    NetLocalGroupAdd
    NetLocalGroupGetInfo
    NetLocalGroupSetInfo
    NetLocalGroupEnum
    NetLocalGroupDel
    NetLocalGroupGetMembers
    NetLocalGroupAddMembers
    NetLocalGroupDelMembers

    LookupAccountName
    LookupAccountSid


81.7. УПРАВЛЕНИЕ КОНСОЛЬЮ

THIS SECTION IS UNDER CONSTRUCTION

Экранные группы

    Консольный ввод/вывод
    Ввод/вывод в текстовом режиме
    Управление курсором

Консоль  (может быть физическая, может быть окно)
    Видимый размер
    Виртуальный размер

Две концепции:
    Напрямую по памяти доступный буфер (Windows)
    Управление через управляющие коды терминала (UNIX)

Экранный буфер
    Массив по всему размеру
        Символ + Аттрибут

Управление курсором
    Скрыть/показать курсор
    Установить размер курсора
    Получить текущие координаты курсора
    Установить курсов в указанное место

Управление кодовыми страницами для вывода
    Влияет на знакогенератор

Собственно два режима работы
    Основной  (когда  данные выводятся на консоль как символы)
    Управляющий

Ввод символа
    Peek
    Read

  Управление курсором

Еще и изменение размера курсора

  Запись в экранный буфер

  Чтение экранного буфера

  Телетайпный вывод

  Ввод с консоли

Windows API
    AllocConsole
    FreeConsole
    GetStdHandle
    SetStdHandle
    GetConsoleWindow
    GetConsoleTitle
    SetConsoleTitle
    GetLargestConsoleWindowSize
    SetConsoleWindowInfo
    CreateConsoleScreenBuffer
    SetConsoleActiveScreenBuffer
    GetConsoleScreenBufferInfo
    SetConsoleScreenBufferSize
    GetConsoleCursorInfo
    SetConsoleCursorInfo
    SetConsoleCursorPosition
    FillConsoleOutputAttribute
    SetConsoleTextAttribute
    WriteConsoleOutputAttibute
    ReadConsoleOutputAttribute
    ReadConsole
    WriteConsole
    ReadConsoleInput
    WriteConsoleInput
    GetNumberOfConsoleInputEvents
    FlushConsoleInputBuffer
    GetNumberOfConsoleMouseButton
    ReadConsoleOutputCharacter
    WriteConsoleOutputCharacter
    FillConsoleOutputCharacter
    ReadConsoleOutput
    WriteConsoleOutput
    SetConsoleMode
    GetConsoleMode
    ScrollConsoleScreenBuffer

UNIX
    termcap
    terminfo
    curses/ncurses


81.8. ПОДСИСТЕМА GUI

THIS SECTION IS UNDER CONSTRUCTION

Архитектура GUI подсистемы

Собственно есть 2 варианта:
    Полное владение экраном
    Частичное владение экраном (например окно).

Графические библиотеки
    Включение видеорежима
    Рисование


81.8.1. ОКНА

THIS SECTION IS UNDER CONSTRUCTION

Окна
    Параметры окна:
        Размер
        Местоположение

    Функции окна:
    создание окна

Отсечения

Видимое окно (может быть частично)
Активное окно (иммет фокус ввода)

Системные кнопки на окне.


81.8.2. СООБЩЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

Сообщения
    Системный источник
        Позиция мыши
        Кнопки мыши
        Нажатия клавиш

    WM_CREATE	Create Window
    WM_DESTROY	Destroy Window
    WM_MOVE		Move window
    WM_SIZEWAIT
    WM_SIZE		Resize windows
    WM_ACTIVATE	Become active/inactive
    WM_SETFOCUS	Input focus
    WM_KILLFOCUS
    WM_SETVISIBLE
    WM_ENABLE
    WM_SETREDRAW
    WM_SETTEXT
    WM_GETTEXT
    WM_GETTEXTLENGTH
    WM_PAINT
    WM_CLOSE
    WM_QUERYENDOFSESSION
    WM_QUIT
    WM_QUERYOPEN
    WM_ERASEBKGND
    WM_SYSCOLORCHANGE
    WM_ENDSESSION
    WM_SYSTEMERROR
    WM_SHOWWINDOW
    WM_CTLCOLOR
    WM_WININITCHANGE
    WM_DEVMODECHANGE
    WM_ACTIVATEAPP
    WM_FONTCHANGE
    WM_TIMECHANGE
    WM_CANCELMODE
    WM_SETCURSOR
    WM_MOUSEACTIVATE
    WM_CHILDACTIVATE
    WM_GETMINMAXINFO
    WM_PAINTICON
    WM_ICONERASEBACKGND
    WM_NEXTDLGCTL
    WM_SPOOLERSTATUS

X:
    ButtonPress
    ButtonRelease
    CirculateNotify
    CirculateRequest
    ClientMessage
    ColormapNotify
    ConfigureNotify
    ConfigureRequest
    CreateNotify
    DestroyNotify
    EnterNotify
    LeaveNotify
    Expose
    FocusIn
    FocusOut
    GraphicExpose
    NuExpose
    GravityNotify
    KeymapNotify
    KeyPress
    KeyRelease
    MapNotify
    UnmapNotify
    MappingNotify
    MapRequest
    MotionNotify
    PropertyNotify
    ReparentNotify
    ResizeRequest
    VisibilityNotify


81.8.3. WIDGETS

THIS SECTION IS UNDER CONSTRUCTION

Widget - как частный вариант окна.

    Button (Command Button)
    CheckBox
    GroupBox
        RadioButton

    Canvas
    ListBox
    ComboBox
    Static Text
    TextField
    Edit
    ScrollBar
    RadioButton
    Rich Edit
    Image

Container
    Panel
    Windows		Dialog
    Frame

По Widgets:
    свойства характерные для widget
    сообщения характерные для widget
        входящие
        исходящие

  Command Button

    Свойства
        Разрешена/Запрещена
        Нажата/Не нажата  (для отрисовки)

    События
        Нажатие/Отпускание
        Разрешение/Запрещение

  Check Box

    Свойства
        Разрешен/Запрещен
        Выбран/Не выбран

    События
        Изменение
    Функции
        Получить текущее состояние
        Выбрать/Не выбрать
        Разрешить/Запретить

  Radio Button

Group Box + Radio Buttons

  ListBox

  ComboBox

  Progress Bar

  Scroll Bar

  Slider

  Text Box

  Text Edit

  Tree View

  Toolbar

  Status bar


81.8.3.1. МЕНЕДЖЕРЫ ПАКОВКИ ВИДЖЕТОВ

THIS SECTION IS UNDER CONSTRUCTION


81.8.4. MENU

THIS SECTION IS UNDER CONSTRUCTION

Menu component

    Глобальное
    Выпадающее

Пункт меню
    Активный/неактивный
    Разделитель
    Submenu


81.8.5. АБСТРАКЦИЯ DEVICE CONTEXT И СИСТЕМЫ КООРДИНАТ

DC Abstraction

Coordinate systems

Misc:
    Color
    Point
    Polygon
    Rectangle
    Region


81.8.6. ПРИМИТИВЫ РИСОВАНИЯ

Canvas - zone for draw

Draw Primitives:

    SetPixel
    GetPixel
    MoveToEx
    GetCurrentPositionEx
    LineTo
    Polyline
    Arc
    Rectangle
    RoundRec
    FillRec
    Ellipse
    Chord
    Pie


81.8.10. ШРИФТЫ

THIS SECTION IS UNDER CONSTRUCTION

    Растровые
    Векторные
        TrueType

Font
FontMetrics


81.8.11. ФОРМАТЫ ГРАФИЧЕСКИХ ФАЙЛОВ

THIS SECTION IS UNDER CONSTRUCTION

    BMP
    GIF
    JPG
    PNG


81.8.20. ГРАФИЧЕСКАЯ АКСЕЛЕРАЦИЯ

THIS SECTION IS UNDER CONSTRUCTION

    OpenGL
    DirectX

2D графика

3D графика

    glVertex2i
    glVertex2f
    glVertex3f

    glBegin(GL_POLYGON)
        glVertex3f()
    glEnd


81.9. ПОДСИСТЕМА ЗВУКА

THIS SECTION IS UNDER CONSTRUCTION

Работа со звуком
    Проигрование файлов в предопределенном для OS формате
    Управление мультимедия устройствами
    Непосредственная работа со звуковыми устройствами

Основные типы устройств вывода
    FM
    Wave
    DSP

Основные типы устройств ввода
    DSP

Основные типы вспомогательных устройств
    Mixer

DSP:
    Параметры
        Частота дискретизации
            типовые частоты
                44100
                22050
                11025
        Число каналов (моно/стерео/большее число каналов)
        Разрядность отчета на канал
                8/16
        Формат кодировки данных

    На специализированных компьютерах типа SGI Octane возможен еще выбор
    источника синхронизации (как правило либо внутренний, либо привязанный к
    A-DAT или внешним разъемам [понятное дело для цифровых форматов]).

Mixer:
    Входной
    Выходной
        для каждого устройства вывода
            Включен/Выключен
            Уровень усиления (по каждому каналу отдельно)

Форматы звуковых данных

API операционных систем для DSP

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

 Windows

UINT waveOutGetNumDevs(void);

MMRESULT waveOutOpen(
    LPHWAVEOUT phwo,
    UINT_PTR uDeviceID,
    LPWAVEFORMATEX pwfx,
    DWORD_PTR dwCallback,
    DWORD_PTR dwCallbackInstance,
    DWORD fdwOpen);

    typedef struct
    {
          WORD  wFormatTag;
          WORD  nChannels;
          DWORD nSamplesPerSec;
          DWORD nAvgBytesPerSec;
          WORD  nBlockAlign;
          WORD  wBitsPerSample;
          WORD  cbSize;

    } WAVEFORMATEX;

MMRESULT waveOutGetDevCaps(
    UINT_PTR uDeviceID,
    LPWAVEOUTCAPS pwoc,
    UINT cbwoc);

    typedef struct
    {
          WORD      wMid;
          WORD      wPid;
          MMVERSION vDriverVersion;
          TCHAR     szPname[MAXPNAMELEN];
          DWORD     dwFormats;
          WORD      wChannels;
          WORD      wReserved1;
          DWORD     dwSupport;
    } WAVEOUTCAPS;

WAVE_FORMAT_1M08	11.025 kHz, mono, 8-bit
WAVE_FORMAT_1M16	11.025 kHz, mono, 16-bit
WAVE_FORMAT_1S08	11.025 kHz, stereo, 8-bit
WAVE_FORMAT_1S16	11.025 kHz, stereo, 16-bit
WAVE_FORMAT_2M08	22.05 kHz, mono, 8-bit
WAVE_FORMAT_2M16	22.05 kHz, mono, 16-bit
WAVE_FORMAT_2S08	22.05 kHz, stereo, 8-bit
WAVE_FORMAT_2S16	22.05 kHz, stereo, 16-bit
WAVE_FORMAT_4M08	44.1 kHz, mono, 8-bit
WAVE_FORMAT_4M16	44.1 kHz, mono, 16-bit
WAVE_FORMAT_4S08	44.1 kHz, stereo, 8-bit
WAVE_FORMAT_4S16	44.1 kHz, stereo, 16-bit
WAVE_FORMAT_96M08	96 kHz, mono, 8-bit
WAVE_FORMAT_96M16	96 kHz, mono, 16-bit
WAVE_FORMAT_96S08	96 kHz, stereo, 8-bit
WAVE_FORMAT_96S16	96 kHz, stereo, 16-bit

WAVECAPS_LRVOLUME	Supports separate left and right volume control.
WAVECAPS_PITCH		Supports pitch control.
WAVECAPS_PLAYBACKRATE	Supports playback rate control.
WAVECAPS_SYNC		The driver is synchronous and will block while playing a buffer.
WAVECAPS_VOLUME		Supports volume control.
WAVECAPS_SAMPLEACCURATE	Returns sample-accurate position information.

MMRESULT waveOutClose(HWAVEOUT hwo);

MMRESULT waveOutPrepareHeader(
    HWAVEOUT hwo,
    LPWAVEHDR pwh,
    UINT cbwh);

    typedef struct wavehdr_tag
    {
          LPSTR              lpData;
          DWORD              dwBufferLength;
          DWORD              dwBytesRecorded;
          DWORD_PTR          dwUser;
          DWORD              dwFlags;
          DWORD              dwLoops;
          struct wavehdr_tag *lpNext;
          DWORD_PTR          reserved;
    } WAVEHDR, *LPWAVEHDR;

MMRESULT waveOutWrite(
    HWAVEOUT hwo,
    LPWAVEHDR pwh,
    UINT cbwh);

MMRESULT waveOutUnprepareHeader(
    HWAVEOUT hwo,
    LPWAVEHDR pwh,
    UINT cbwh);

void CALLBACK waveOutProc(
    HWAVEOUT hwo,
    UINT uMsg,
    DWORD_PTR dwInstance,
    DWORD_PTR dwParam1,
    DWORD_PTR dwParam2
);

WOM_CLOSE	Sent when the device is closed using the waveOutClose function.
WOM_DONE	Sent when the device driver is finished with a data block sent
        using the waveOutWrite function.
WOM_OPEN	Sent when the device is opened using the waveOutOpen function.

MMRESULT waveOutPause(HWAVEOUT hwo);
MMRESULT waveOutRestart(HWAVEOUT hwo);
MMRESULT waveOutReset(HWAVEOUT hwo);

MMRESULT waveOutGetPosition(
    HWAVEOUT hwo,
    LPMMTIME pmmt,
    UINT cbmmt);

MMRESULT waveOutGetVolume(
    HWAVEOUT hwo,
    LPDWORD pdwVolume);

MMRESULT waveOutSetVolume(
    HWAVEOUT hwo,
    DWORD dwVolume);

 Windows

UINT waveInGetNumDevs(void);

MMRESULT waveInOpen(
    LPHWAVEIN phwi,
    UINT_PTR uDeviceID,
    LPWAVEFORMATEX pwfx,
    DWORD_PTR dwCallback,
    DWORD_PTR dwCallbackInstance,
    DWORD fdwOpen);

MMRESULT waveInGetDevCaps(
    UINT_PTR uDeviceID,
    LPWAVEINCAPS pwic,
    UINT cbwic);

    typedef struct
    {
          WORD      wMid;
          WORD      wPid;
          MMVERSION vDriverVersion;
          TCHAR     szPname[MAXPNAMELEN];
          DWORD     dwFormats;
          WORD      wChannels;
          WORD      wReserved1;
    } WAVEINCAPS;

MMRESULT waveInClose(
    HWAVEIN hwi);

MMRESULT waveInPrepareHeader(
    HWAVEIN hwi,
    LPWAVEHDR pwh,
    UINT cbwh);

MMRESULT waveInUnprepareHeader(
    HWAVEIN hwi,
    LPWAVEHDR pwh,
    UINT cbwh);

MMRESULT waveInAddBuffer(
    HWAVEIN hwi,
    LPWAVEHDR pwh,
    UINT cbwh);

void CALLBACK waveInProc(
    HWAVEIN hwi,
    UINT uMsg,
    DWORD_PTR dwInstance,
    DWORD_PTR dwParam1,
    DWORD_PTR dwParam2);

MMRESULT waveInGetPosition(
    HWAVEIN hwi,
    LPMMTIME pmmt,
    UINT cbmmt);

    typedef struct mmtime_tag
    {
          UINT  wType;
          union
        {
                DWORD ms;
                DWORD sample;
                DWORD cb;
                DWORD ticks;
                struct
            {
                      BYTE hour;
                      BYTE min;
                      BYTE sec;
                      BYTE frame;
                      BYTE fps;
                      BYTE dummy;
                      BYTE pad[2];
                } smpte;
                struct
            {
                      DWORD songptrpos;
                } midi;
          } u;
    } MMTIME, *PMMTIME, *LPMMTIME;

TIME_BYTES
TIME_MIDI
TIME_MS
TIME_SAMPLES
TIME_SMPTE
TIME_TICKS

MMRESULT waveInStart(HWAVEIN hwi);
MMRESULT waveInStop(HWAVEIN hwi);
MMRESULT waveInReset(HWAVEIN hwi);

Windows API
    wave
        waveOutGetPitch
        waveOutSetPitch
        waveOutGetPlaybackRate
        waveOutSetPlaybackRate
        waveOutMessage
        waveOutBreakLoop

        waveInMessage

        mixerClose
        mixerGetControlDetails
        mixerGetDevCaps
        mixerGetLineControls
        mixerGetLineInfo
        mixerGetNumDevs
        mixerMessage
        mixerOpen
        mixerSetControlDetails

    DirectSound
        IDirectSound8		device
        IDirectSoundBuffer8	secondary buffers
        IDirectSoundNotify8
        IDirectSoundBuffer	primary buffer

        IDirectSoundCapture8
        IDirectSoundCaptureBuffer8

MacOS
    SndNewChannel
    SndDisposeChannel
    SndPlayDoubleBuffer

UNIX
    NAS

OSS (Open Sound System) is standart for sound for X applications.

    OSS support by Linux, FreeBSD, SCO OpenServer, SCO UNIXware, Solaris
and some other platforms.

Include file is "soundcard.h"

Main idea is special IOCTLs to devices:

    /dev/mixer
        SOUND_MIXER_READ_DEVMASK
        SOUND_MIXER_READ_RECMASK
        SOUND_MIXER_READ_STEREODEVS
        SOUND_MIXER_READ_CAPS
        SOUND_MIXER_READ(SOUND_MIXER_MIC)
        SOUND_MIXER_READ(xxx)
        SOUND_MIXER_WRITE(xxx)
        SOUND_MIXER_READ_RECSRC
    /dev/sndstat
    /dev/dsp
    /dev/audio
        SNDCTL_DSP_SETFMT		set data format
        SNDCTL_DSP_GETFMTS 		get supported formats
        SNDCTL_DSP_CHANNELS		selecting mono/stereo
        SNDCTL_DSP_SPEED		selectiing sampling rate
        SNDCTL_DSP_SYNC			synchronize
        SNDCTL_DSP_RESET		stop
        SNDCTL_DSP_POST			pause
        SNDCTL_DSP_GETBLKSIZE
                SNDCTL_DSP_GETISPACE		buffers info
        SNDCTL_DSP_GETOSPACE		buffers info
        SNDCLT_DSP_GETODELAY
        SNDCTL_DSP_SETFRAGMENT
        SNDCTL_DSP_GETIPTR		buffers info
        SNDCTL_DSP_GETOPTR		buffers info
        SNDCTL_DSP_GETERROR
                SNDCTL_DSP_SETTRIGGER		for precise time start/stop
        SNDCTL_DSP_SETDUPLEX		set duplex mode
        read()				transfer data
        write()
    /dev/sequencer
    /dev/music
    /dev/midi
        SNDCTL_MIDI_PRETIME		timeout to first MIDI message
        read()
        write()				MIDI messages transfer
    /dev/dmfm                    		Direct FM interface
        struct	dm_fm_voice{}
        struct  dm_fm_note{}
        struct  dm_fm_param{}
        FM_IOCTL_RESET
        FM_IOCTL_SET_MODE
        FM_IOCTL_SET_VOICE		modulation etc
        FM_IOCTL_PLAY_NOTE
        FM_IOCTL_SET_PARAMS
        FM_IOCTL_SET_OPL		connection type
    /dev/dmmidi


81.9.10. ФОРМАТЫ ЗВУКОВЫХ ФАЙЛОВ

THIS SECTION IS UNDER CONSTRUCTION

    WAV
    MID
    итд


81.10. УПРАВЛЕНИЕ ПЕРЕФИРИЙНЫМИ УСТРОЙСТВАМИ

THIS SECTION IS UNDER CONSTRUCTION

В этой секции мы будем рассматривать OS-интерфейс-специфичные  вещи
по отношению к управлению типовыми перефирийными устройствами.


81.10.1. ПОСЛЕДОВАТЕЛЬНЫЙ ПОРТ

THIS SECTION IS UNDER CONSTRUCTION

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

Например для Windows:

    IOCTL_SERIAL_GET_BAUD_RATE

    IOCTL_SERIAL_SET_BAUD_RATE
    IOCTL_SERIAL_SET_QUEUE_SIZE

    IOCTL_SERIAL_GET_LINE_CONTROL
    IOCTL_SERIAL_GET_DTRRTS

    IOCTL_SERIAL_SET_LINE_CONTROL
    IOCTL_SERIAL_SET_BREAK_ON
    IOCTL_SERIAL_SET_BREAK_OFF
    IOCTL_SERIAL_SET_DTR
    IOCTL_SERIAL_CLR_DTR
    IOCTL_SERIAL_SET_RTS
    IOCTL_SERIAL_CLR_RTS
    IOCTL_SERIAL_SET_XOFF
    IOCTL_SERIAL_SET_XON

    IOCTL_SERIAL_RESET_DEVICE


81.10.2. ПАРАЛЕЛЬНЫЙ ПОРТ

THIS SECTION IS UNDER CONSTRUCTION

    IOCTL_PAR_QUERY_INFORMATION
    IOCTL_PAR_SET_INFORMATION
    IOCTL_IEEE1284_GET_MODE
    IOCTL_IEEE1284_NEGOTIATE


81.10.3. ПЕЧАТЬ

THIS SECTION IS UNDER CONSTRUCTION

    Windows: тот же GUI для рисования, просто рисуем на принтер


81.10.4. СКАНИРОВАНИЕ

THIS SECTION IS UNDER CONSTRUCTION

    TWAIN
        DSM_Entry()	Source Manager
        DS_Entry()	Source

        DG_CONTROL
            MSG_OPENDSM		open source manager
            MSG_CLOSEDSM		close source manager
            MSG_CLOSEDS
            MSG_GETDEFAULT
            MSG_GETFIRST
            MSG_GETNEXT
            MSG_OPENDS
            MSG_USERSELECT		pop up source select windos
            MSG_GET
            MSG_GETCURRENT
            MSG_GETDEFAULT
            MSG_RESET
            MSG_SET
        DG_IMAGE
            DAT_CIECOLOR
            DAT_GRAYRESPONSE
            DAT_IMAGEINFO
            DAT_IMAGEFILEXFER	transfer via disk file
            DAT_IMAGEMEMXFER
            DAT_IMAGENEGATIVEXFER
            DAT_JPEGCOMPRESSION
            DAT_PALLETE8
            DAT_RGBRESPONSE
               DG_AUDIO

        1) Pre-session
        2) Source Manager loaded
        3) Source Manager open
        4) Source open
        5) Source enabled
        6) Transfer ready
        7) Transferring

    WIA (Windows Image Aquisition API)
        IWiaDevMgr
        IWiaEventCallback
        IEnumWiaItem
        IScanProfile
        IScanProfileMgr
        IScanProfileUI
        IWiaDataTransfer
        IWiaDataCallback
        IWiaTransfer
        IWiaImageFilter
        IWiaItem
        IWiaNotifyDevMgr
        IWiaPreview
        IWiaPropertyStorage
        IWiaVideo


81.10.5. REAL TIME ВИДЕО-ВВОД

THIS SECTION IS UNDER CONSTRUCTION


81.10.6. CUSTOM USB УСТРОЙСТВА

THIS SECTION IS UNDER CONSTRUCTION

    USB specific


82. СИНХРОНИЗАЦИЯ

THIS SECTION IS UNDER CONSTRUCTION

В этой секции мы будем изучать синхронизацию

Примитивы синхронизации
    Spin-/Wait-
        Mutex
        Semaphore
        RW-lock
        Seq-lock
        Event
    Атомарные операции

    Таймеры
    Критические секции
    Барьеры


82.1. ПРИМИТИВЫ СИНХРОНИЗАЦИИ

Основа - низкоуровневые операции

    Синхронизация
     /         \
       spin        wait

spin - поток выполнений (нить) остается активным и продолжает пытаться захватить ресурс
wait - поток выполнения (нить) засыпает пока ресурс не будет освобожден

 --------------------------------------------------
                  Scalable  Fair	Sleeps
 --------------------------------------------------
spin-mutex              No        No      No
queuing-mutex		Yes	  Yes	  No
spin-semaphore	        No	  No	  No
queuing-spin-semaphore  Yes	  Yes	  No
spin-rw-lock	        No        No      No
queuing-spin-rw-lock    Yes       Yes     No
 --------------------------------------------------
mutex			OSdepend OSdepend Yes
semaphore		OSdepend OSdepend Yes
rw-lock		        OSdepend OSdepend Yes
 --------------------------------------------------

  Spin-семантика

  Locked операции на шине

Прочтите секцию 35.2.1.4.2. СЕМАФОРНЫЕ ОПЕРАЦИИ
Там описаны операции подобного рода в различных семействах процессоров

  Mutex

Mutex - это бинарный семафор.

    операции
    --------
    init   		первоначальная инициализация переменной мьютекса
    trylock		попытка блокировки мьютекса - возращение статуса попытки
    lock		блокировка мьютекса (собсвенно это spin-lock)
    unlock		освобождение уже захваченного мьютекса

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

Реализуется как правило нижнеуровневыми командами вида:
Для x86.
    LOCK XCHG
    LOCK битовые операции (BTS, BTC)

    XCHG	dest, src			dest < --- > src
    BTS	dest, bit_number		CF = BIT(dest, bit_number)
                        BIT(dest, bit_number) = 1
    BTC	dest, bit_number		CF = BIT(dest, bit_number)
                        BIT(dest, bit_number) = 0

Пример реализации:
    ---------------------------------------------------------------------
    mutex_init(&mutex, MUTEX_UNLOCKED)		mov	[mutex], 0
    mutex_init(&mutex, MUTEX_LOCKED)		mov	[mutex], 1
    ---------------------------------------------------------------------
bool	mutex_trylock(&mutex)				mov	eax, 1
                           lock xchg	[mutex],eax
                            or	eax,eax
                            mov	eax, FALSE
                            mov	ebx, TRUE
                            cmovz	eax, ebx
                            ret
    ---------------------------------------------------------------------
    mutex_unlock(&mutex)			   lock mov    [mutex],0
    ---------------------------------------------------------------------

пример реализации на битовых операциях (используем бит # N)
    ---------------------------------------------------------------------
bool	mutex_trylock(&mutex)			   lock	bts	[mutex], N
                            mov	eax, FALSE
                            mov	ebx, TRUE
                            cmovc	eax, ebx
                            ret
    ---------------------------------------------------------------------
    mutex_unlock(&mutex)			   lock btc	[mutex], N
    ---------------------------------------------------------------------

  Пример реализации

x86 инструкция XCHG

Пример как организовывать мьютекс

Захват свободного мьютекса:

Попытка захвата занятого мьютекса

Освобождение мьютекса

  Spin lock

Простейший spin-lock (собственно spin-lock) - это захват мьютекса.

Пример реализации:
    ---------------------------------------------------------------------
    spinmutex_lock(&mutex)			?spin_loop:
                             mov	eax,1
                          lock  xchg	[mutex],eax
                            or	eax,eax
                            jz	?lock_success
                            ;; wait
                            jmp	?spin_loop
                        ?lock_success:
                            ret
    ---------------------------------------------------------------------

Основная проблема spin-lock, это то что процессор сидящий в spin-loop переодически
пытается сделать лоченную операцию к шине, что приводит к потере быстродействия системы,
так как лоченные операции выполняются на порядок медленнее чем обычные.

Есть команда которая ждет определенное фиксированное количество времени
        PAUSE

Поэтому в современные микропроцессоры стали вводить команды оптимизирующие spin-locks.
Например современные процессоры Intel имеют команды MONITOR и MWAIT
Команда MONITOR указывает адресс который будет мониториться (в EAX), команда MWAIT осуществляет ожидание,
Если происходит обращение к указанному адрессу (понятное дело из другого ядра или процессора или
bus-master оборудования), то команда MWAIT заканчивает свое выполнение и
управление передается следующей команды (в зависимости от параметров передаваемых в регистрах
MWAIT может также прерываться а может не прерываться по прерываниям, но по NMI, SMI будет все равно
прерываться).

Вот так будет выглядеть spin-lock используя эти инструкции.

    ---------------------------------------------------------------------
    spinmutex_lock(&mutex)			?spin_loop:
                            mov	eax,1
                           lock xchg	[mutex],eax
                            or	eax,eax
                            jz	?lock_success
                            xor	ecx,ecx
                            xor	edx,edx
                            lea	eax,[mutex]
                            monitor
                            mwait
                            jmp	?spin_loop
                        ?lock_success:
                            ret
    ---------------------------------------------------------------------

Собственно spin-lock надо использлвать только на короткое время.
В случае kernel программирования может возникнуть необходимость в IRQ safe версиях этих функций.
Тогда они должны сохранить флаг прерывания, и запретить прерывания во время выполнения.

Оптимизация spin-locks

С точки зрения кэширования

Cache Coherence:

Write-Invalidate:

Write-Update

Spin on Test&Set
    -   Test and Set захватывает шину - падает эффективность
            while(Test_and_Set(&lock) == BUSY) ;	// spin

Spin on Read
    +   В основном обращения идут к cache
    -   После того как кто-то отпускает lock, все начинают долбиться по
        Test_and_Set, это занимает много времени, особенно если у cache политика не
        обновлять внешние записи, а инвалидировать

            while(1)
            {
                while(lock == BUSY) ;  // spin  - чтение из cache
                if (Test_and_Set(&lock) == BUSY) break;
            }

MESI протокол:

    ---------------------------------------------------------------------
    spinmutex_lock(&mutex)			?spin_loop:
                            cmp	[mutex],0	; From local cache
                            jnz	?spin_loop
                             mov	eax,1
                          lock  xchg	[mutex],eax
                            or	eax,eax
                            jz	?lock_success
                            jmp	?spin_loop
                        ?lock_success:
                            ret
    ---------------------------------------------------------------------

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

 Windows

Windows (Kernel Mode):

    typedef ULONG_PTR KSPIN_LOCK;

    VOID KeInitializeSpinLock(IN PKSPIN_LOCK  SpinLock);
    VOID KeAcquireSpinLock(PKSPIN_LOCK  SpinLock, PKIRQL OldIrql);
    VOID KeReleaseSpinLock(PKSPIN_LOCK  SpinLock, KIRQL NewIrql);

Когда Windows Kernel захватывает spin-lock он повышает уровень выполнение нити до
DISPATCH_LEVEL. Соответсвенно когда отпускает то востанавливает уровень выполнения
(он храниться в переменной типа KIRQL).

    VOID KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK  SpinLock);
    VOID KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK  SpinLock);

Для однопроцессорной системы реализация spin-lock еще проще - не надо захватывать
spin-mutex, можно просто поднять приоритет нити.

Специальный случай для синхронизации с ISR:

    KIRQL KeAcquireInterruptSpinLock(IN PKINTERRUPT  Interrupt);
    VOID  KeReleaseInterruptSpinLock(IN PKINTERRUPT  Interrupt,  IN KIRQL  OldIrql);

POSIX 1003.1j

 UNIX

    int  pthread_spin_init(pthread_spinlock_t* spiner, int pskcred);
    int  pthread_spin_destroy(pthread_spinlock_t* spiner);
    int  pthread_spin_lock(pthread_spinlock_t* spiner);
    int  pthread_spin_trylock(pthread_spinlock_t* spiner);
    int  pthread_spin_unlock(pthread_spinlock_t* spiner);

  Атомарные операции

    Atomic Exchange

    Типичная атомарная операция

    Atomic Compare Exchange

Как правило используются атомарные операции
    Atomic Increment		добавляет 1
    Atomic Decrement		вычитает  1
    Atomic Add			сложение
    Atomic Subtract			вычитание   (сложение с отрицательным числом)
    Atomic Exchange			обмен
    Atomic Exchange Pointer
    Atomic Exchange Add
    Atomic Compare  Exchange
    Atomic And
    Atomic Or
    Atomic Xor

Пример атомарной операции для сложения вычитания

Типовой синтаксис:

    NewValue InterlockedIncrement(Address)
    NewValue InterlockedDecrement(Address)

    OldValue InterlockedExchange(Address, NewValue)
    OldValue InterlockedExchangeAdd(Address, Increment)
    OldValue InterlockedCompareExchange(Address, NewValue, Comparand)

для x86 напрямую мапируются в операции процессора:

 Windows

LONG     InterlockedExchange(LONG volatile* Target, LONG Value);	// XCHG   target, value
LONG     InterlockedExchangeAdd(LONG volatile* Addend, LONG Value);	// XADD   target, value
LONG     InterlockedCompareExchange(LONG volatile* Destination, 	// CMPXCHG
                    LONG Exchange, LONG Comparand);
LONG     InterlockedIncrement(LONG volatile* Target);			// XADD   target, 1
LONG	 InterlockedDecrement(LONG volatile* Target);			// XADD   target, -1

LONG     InterlockedAnd(LONG volatile* Destination, LONG Value);	// CMPXCGG complex code
LONG     InterlockedOr(LONG volatile* Destination, LONG Value);		// CMPXCHG complex code
LONG     InterlockedXor(LONG volatile* Destination, LONG Value);	// CMPXCHG complex code

BOOLEAN  InterlockedBitTestAndReset(LONG volatile* Base, LONG Bit);	// LOCK BTR
BOOLEAN  InterlockedBitTestAndSet(LONG volatile* Base, LONG Bit);	// LOCK BTS

LONG     InterlockedAdd(LONG volatile* Addend, LONG Value);		// XADD target, value
                                    // return new value

LONGLONG InterlockedIncrement64(LONGLONG volatile* Addend);		// CMPXCHG8B complex code
LONGLONG InterlockedDecrement64(LONGLONG volatile* Addend);		// CMPXCHG8B complex code
LONGLONG InterlockedExchange64(LONGLONG volatile* Target,               // CMPXCHG8B complex code
                   LONGLONG Value);
LONGLONG InterlockedExchangeAdd64(LONGLONG volatile* Addend,		// CMPXCHG8B complex code
                  LONGLONG Value);
LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, 	// CMPXCHG8B complex code
                      LONGLONG Exchange,
                                  LONGLONG Comparand);

BOOLEAN  InterlockedBitTestAndReset64(LONG64 volatile* Base, LONG64 Bit); // LOCK BTR
BOOLEAN  InterlockedBitTestAndSet64(LONG64 volatile* Base, LONG64 Bit);   // LOCK BTS

LONGLONG InterlockedAdd64(LONGLONG volatile* Addend, LONGLONG Value);
LONGLONG InterlockedAnd64(LONGLONG volatile* Destination, LONGLONG Value);
LONGLONG InterlockedOr64(LONGLONG volatile* Destination,LONGLONG Value);
LONGLONG InterlockedXor64(LONGLONG volatile* Destination,LONGLONG Value);

PVOID    InterlockedCompareExchangePointer(PVOID volatile* Destination,	// CMPXCHG
                       PVOID Exchange,
                       PVOID Comparand);

PVOID    InterlockedExchangePointer(PVOID volatile* Target,PVOID Value); // XCHG

Принцип атомарных операций:
    RMW  (Read-Modify-Write)

    CMPXCHG	r/m,r
        if accumulator = dest
        {
            ZF <- 1
            dest <- src
        } else {
            ZF <- 0
            accumulator <- dest
        }

    CMPXCHG8B	m64
        if (EDX:EAX == dest)
        {
            ZF <- 1
            dest <- ECX:EBX
        } else {
            ZF <- 0
            EDX:EAX <- dest
        }

Кстати x64 имеет команду CMPXCHG16B  m128.

Реализации атомарных операций как правило оптимизирована командами которые лочат шину
на примере сложения x86:

    ---------------------------------------------------------------------
    void interlocked_add32(&variable, value)	   lock	add	[variable],value
    ---------------------------------------------------------------------

Но не всегда для всех размеров данных, например для 64-бит данных на x86 придется уже
использовать более сложные методы, которые используют команду Compare exchange.

LONGLONG  InterlockedAnd64(LONGLONG* Destination, LONGLONG Value)
{
    LONGLONG  Old;

    do
    {
        Old = *Destination;
    } while (InterlockedCompareExchange64(Destination, Old & Value, Old) != Old);
    return	Old;
}

Зачем нужны атомарные операции?
Две цели:
    1) Реализация семафоров и мьютексов
    2) Реализация работы с shared variables не обкладывая их мьютексами

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

QNX:
    void atomic_*(volatile unsigned* D, unsigned S)
    unsigned atomic_*_value(volatile unsigned* D, unsigned S)
                        // return previous value

        add
        sub
            clr		(*D) &= ~S
        set		(*D) |= S
        toggle		(*D) ^= S

Что делать если архитектура не поддерживает необходимую атомарную операцию?

Например x86 Windows сложение 32-битных чисел осуществляется как атомарная операция
которая использует команду XADD:

    LONG result = InterlockedAdd(&variable, increment);

Но для 64-бит в x86 нет атомарных операций которые это делают.
В этом случае приходиться использовать дополнительный spin-lock  который защищает
данные (это уже игра с системой):

    LONGLONG  ExInterlockedAddLargeInteger(PLONGLONG variable,
                           LONGLONG  increment,
                           PKSPIN_LOCK spinlock)
    {
        LONGLONG oldvalue;

        AcquireSpinLock(&spinlock);	// Код чисто характеристический
                        // В реальности есть еще IRQL заморочки

        oldvalue = * variable;
        * variable += increment;

        ReleaseSpinLock(&spinlock);
        return	oldvalue;
    }

Конечно для 64-бит можно добиться такого же эффекта с помощью CMPXCHG8B,
но если надо например изменять  атомарно уже 128-бит переменную, то придеться
пользоваться системными примитивами для синхронизации.

Linux:

    ATOMIC_INIT
    atomic_read
    atomic_set
    atomic_add
    atomic_sub
    atomic_inc
    atomic_dec
    atomic_sub_and_test
    atomic_add_negaative
    atomic_dec_and_test
    atomic_inc_and_test

    set_bit
    clear_bit
    change_bit
    test_and_set_bit
    test_and_clear_bit
    test_and_change_bit
    test_bit

  Семафор

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

В настоящее время для поддержки семафоров в некоторых современных проессорах существуют
специальные команды. Например для x86 такой командой является XADD

    XADD	dest,src			temp = src + dest
                        src  = dest
                        dest = tmp

    операции
    --------
    init   		первоначальная инициализация переменной семафора
    trylock		попытка блокировки семафора - возращение статуса попытки
    lock		блокировка семафора (собсвенно это spin-semaphore)
    unlock		освобождение уже захваченного семафора

    -----------------------------------------------------------------------
    semaphore_init(&semaphore)			mov	[semaphore], 0
    -----------------------------------------------------------------------
bool	semaphore_trylock(&semaphore)			mov	eax, 1
                        lock	xadd	[semaphore], eax
                            cmp	eax, MAX_VALUE
                            mov	eax, TRUE
                            jnc	?success
                            mov	eax, -1
                        lock	xadd	[semaphore],eax
                            mov	eax, FALSE
                        ?success:
                            ret
    -----------------------------------------------------------------------
    semaphore_unlock(&semaphore)		lock	dec	[semaphore]
    -----------------------------------------------------------------------

Пример организации семафора

Отрицательное значение - семафор свободен
Положительное или 0 - семафор занят
Например если мы хотим семафор(2), его надо проинициализировать числом -2

Захват свободного семафора:

Захват свободного семафора:

Попытка захвата занятого семафора:

Откат после неудачной попытки захвата:

Освобождение семафора:

соответсвенно захват
    -----------------------------------------------------------------------
    spinsemaphore_lock(&semaphore)		?spin_loop
                             mov	eax,1
                          lock  xadd	[semaphore],eax
                            cmp	eax, MAX_VALUE
                            jc	?lock_success
                            ;; wait
                            jmp	?spin_loop
                        ?lock_success:
                            ret
    -----------------------------------------------------------------------

реализация семафора на базе mutexa:

    -----------------------------------------------------------------------
bool	semaphore_trylock(&semaphore)		spinmutex_lock(&mutex)
                        if (*semaphore < MAX_VALUE)
                        {
                            (*semaphore)++;
                            mutex_unlock(&mutex);
                            return	TRUE;
                        }
                        mutex_unlock(&mutex);
                        return	FALSE;
    -----------------------------------------------------------------------
    semaphore_unlock(&semaphore)		spinmutex_lock(&mutex)
                        (*semaphore)--;
                        mutex_unlock(&mutex)
    -----------------------------------------------------------------------
    spinsemaphore_lock(&semaphore)		while(semaphore_trylock(&semaphore) != TRUE) ;
    -----------------------------------------------------------------------

  RW-lock

RW-lock - это дальнейшее совершенствование структуры.
Есть какая структура данных, которую надо защищать.
И есть два вида агентов которые к ней обращаются - читатели и писатели.
    Читатели могут читать паралельно друг другу (shared)
    Пока есть читатели писать нельзя

    Писатель может быть только один (exclusive)
    Пока есть писатель другим нельзя ни читать не писать

Сейчас мы будем рассматривать RW-spin-lock

    операции	читатель		писатель
    --------------------------------------------------------
    init			     rwlock_init
    trylock		reader_trylock          writer_trylock
    lock		reader_lock		writer_lock
    unlock		reader_unlock		writer_unlock
    --------------------------------------------------------

Собственно одна из идей реализации - это хранить состояние RW-lock
    free
    read_acquired
    write_acquired
и собственно говоря счетчик читателей

    -----------------------------------------------------------------------
    rwlock_init(&rwlock)			rwlock.state  = RWLOCK_FREE;
                        rwlock.rcount = 0;
                        mutex_init(&mutex);
    -----------------------------------------------------------------------
bool	reader_trylock(&rwlock)			mutex_lock(&mutex);
                        switch(rwlock.state)
                        {
                        case RWLOCK_FREE:
                            rwlock.state = RWLOCK_READ_ACQUIRED;
                            // fall throught
                        case RWLOCK_READ_ACQUIRED:
                            rwlock.rcount++;
                            mutex_unlock(&mutex)
                            return	TRUE;
                        default:  // RWLOCK_WRITE_ACQUIRED
                            mutex_unlock(&mutex);
                            return	FALSE;
                        }
    -----------------------------------------------------------------------
    reader_unlock(&rwlock)			mutex_lock(&mutex)
                        rwlock.rcount--;
                        if (rwlock.rcount == 0)
                        {
                            rwlock.state = RWLOCK_FREE;
                        }
                        mutex_unlock(&mutex);
    -----------------------------------------------------------------------
    reader_lock(&rwlock)			while (reader_trylock(&rwlock) != TRUE) ;
    -----------------------------------------------------------------------
bool	writer_trylock(&rwlock)			mutex_lock(&mutex)
                        if (rwlock.state != RWLOCK_FREE)
                        {
                            mutex_unlock(&mutex);
                            return	FALSE;
                        }
                        rwlock.state = RWLOCK_WRITE_ACQUIRED;
                        mutex_unlock(&mutex);
    -----------------------------------------------------------------------
    writer_unlock(&rwlock)			mutex_lock(&mutex);
                        rwlock.state = RWLOCK_FREE;
                        mutex_unlock(&mutex);
    -----------------------------------------------------------------------
    writer_lock(&rwlock)			while (writer_trylock(&rwlock) != TRUE) ;
    -----------------------------------------------------------------------

чем такая имплементация плоха - если постоянно и часто идут чтения то writer может и не захватить
RWlock, а как правило хочеться, чтобы он его все таки захватил.
решается это добавлением дополнительного состояния "write pending", при котором новым читателям не дают
возможность захватить rwlock, пока не будет записи.
И кстати все это можно реализовать с помощью одного единственного слова памяти:

Дальнейшее развитие - уже сбалансированные политики.

Собственно для однопроцессорных машин RWlock - это некоторый аналог spin-lock (если reader или writer вошел то
пока не вышел ничего хорошего). Реальное преймущество RWlock идет в многопроцессорных машинах при
паралельном чтении.

Иногда бывает вариант, который имеет функуию upgrade_to_writer() которая превращает reader,
который уже находиться внутри lockа, во writer.

собственно кроме RWlock бывает еще и RW-semaphore. Он имеет такую же семантику, но ограничение
на количество одновременных читателей. Соответсвенно изменения касаются reader_trylock:

    -----------------------------------------------------------------------
bool	reader_trylock(&rwlock)			mutex_lock(&mutex);
                        switch(rwlock.state)
                        {
                        case RWLOCK_FREE:
                            rwlock.state = RWLOCK_READ_ACQUIRED;
                            // fall throught
                        case RWLOCK_READ_ACQUIRED:
                            if (rwlock.rcount >= MAX_VALUE)
                            {
                                mutex_unlock(&mutex);
                                return	FASLE;
                            }
                            rwlock.rcount++;
                            mutex_unlock(&mutex)
                            return	TRUE;
                        default:  // RWLOCK_WRITE_ACQUIRED
                            mutex_unlock(&mutex);
                            return	FALSE;
                        }
    -----------------------------------------------------------------------

  Seq-lock

Еще одно изобретение - это sequential lock. Он может использоваться когда в случаях типа RWlock, но
идет защита данных про которых строго известно их распределение в памяти (не динамические цепочки),
например какая то статистика итд.

Данная блокировка позволяет не использовать spin-lock при чтении, ограничиваясь обычным считыванием
переменной счетчика sequent лока. Если до начала операции и после ее окончания значение счетчика
одинаково - значит мы считали данные в consistent состоянии

    Операции	reader			writer
    -----------------------------------------------------
    init			seqlock_init
    lock					writer_seqlock
    unlock					writer_sequnlock
    beginread	reader_seqbegin
    endread		reader_seqretry
    -----------------------------------------------------

Data:
    seqlock.counter	- счетчик seqlock
    mutex		- мьютекс для записи

    -----------------------------------------------------------------------
    seqlock_init(&seqlock)			seqlock.counter = 0;
                        init_mutex(&mutex)
    -----------------------------------------------------------------------
    writer_seqlock(&seqlock)		mutex_lock(&mutex)
                        seqlock.counter++;
    -----------------------------------------------------------------------
    writer_sequnlock(&seqlock)		seqlock.counter--
                        mutex_unlock(&mutex)
    -----------------------------------------------------------------------
int	reader_seqbegin(&seqlock)		return	atomic_read(seqlock.counter)
    -----------------------------------------------------------------------
bool	reader_seqretry(&seqlock, int prev)	if (atomic_read(seqlock.counter) != prev)
                        {
                            return TRUE;
                        }
                        return FALSE;
    -----------------------------------------------------------------------

В результате семантика writera имеет вид:

    writer_seqlock(&seqlock);
    // WRITE actions
    writer_sequnlock(&seqlock);

а семантика читателя:

    int	seq;
    do
    {
        seq = reader_seqbegin(&seqlock);
        // READ actions
    } while( reader_seqretry(&seqlock, seq));

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

    structures w/o pointers a-la statistics

    +-----------------+
    |   data	  |
    +-----------------+
    |   data	  |
    +-----------------+

Seq-lock cинхронизация и Out-Of-Order Execution

Out-of-order execution:
    need barrier
    barrier is locked access
        LOCK	xxx
    or special commands
        MFENCE
        SFENCE
        LFENCE

    на примере SeqLock

        прочитали LockCounter 1й раз
        прочитали данные
        прочитали LockCounter 2й раз

    поскольку Out-of-order execution то
    возможна ситуация типа

        прочитали LockCounter 1й раз
        прочитали LockCounter 2й раз
        прочитали данные
    что в общем то не то что мы хотели получить.

    что бы ее избежать делаем memory barrier по чтению

        прочитали LockCounter 1й раз
        прочитали данные
        Read Memory Barrier
        прочитали LockCounter 2й раз

    На самом деле их 2 типа
        Барьеры оптимизации (оптимизирующий компилятор переставляет)
        Барьеры памяти  (процессор выполняет не в порядке)

    Собственно для писателей тоже нужен барьер, но уже на запись
        прибавили SeqLock
        Барьер по записи
        обновили данные
        Барьер по записи
        прибавили SeqLock

  Примитивы для однопроцессорных машин

Для однопроцессорных машин можно не применять Locked операции на шине - они занимают
слишком много времени.
Достаточно запретить прерывания на короткое время нужное для доступа к данным:

    -------------------------------------------------------------------------
    bool	sp_mutex_trylock(&mutex)		cli
                            mov	eax,[mutex]
                            mov	[mutex], 1
                            sti
                            ret
    -------------------------------------------------------------------------
    bool	sp_semaphore_trylock(&mutex)		cli
                            mov	eax, [sem]
                            add	eax, 1
                            mov	[sem], eax
                            cmp	eax, MAX_VALUE
                            jnc	?success
                            sub	eax, 1
                            mov	[sem], eax
                            mov	eax, FALSE
                            sti
                            ret
                        ?success:
                            mov	eax, TRUE
                            sti
                            ret
    -------------------------------------------------------------------------

  wait-семантика

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

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

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

Как правило объекты для ожидания являются именованными.

Например в Windows есть:
    WaitForSingleObject()
    WaitForMultipleObjects()

Может и не дождаться - если система обнаружит dead lock
        WAIT_OBJECT_0
        WAIT_ABANDONED
        WAIT_TIMEOUT
        WAIT_FAILED

Waitable Objects

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

Именованные используются для работы между совершенно различными
процессами.

Как выглядит Waitable Object
Во первых это spin-mutex который его защищает
Во вторых владелец, в третих список тех кто ждет

    +------------+
    |  Mutex     |
    +------------+             +--------------+
    |  Owner     |------------>|Process/Thread|
    +------------+             +--------------+
    |  Waiters   |
    +------------+

Waiters могут быть построены в виде очереди
(так удобнее отслеживать кого отпускать первого если идет pulse)
Как правило в системах есть определенное ограничение не ресурсы
из серии - объект могут ждать не более N processed/thread.
Бывают случаи когда при создании объектов можно указать
максимальное количество ожидающих.

Во вторых структуры process/thread имеют указатели на объекты которыми
они владеют и на объекты которые они ждут.

Это позволяет во первых отслеживать deadlocks (см следущую секцию),
а во вторых в случае завершения нити/процесса - позволяет отпускать
залоченные ими ресурсы, а так же удалять из списка ждущих.

    +-------------+  own  +----------+     +---------+
    |   Process   |------>|  Object  |---->|  Object |
    |   --------  |       +----------+     +---------+
    |   Thread    |
    +-------------+
        |       wait  +----------+     +---------+
        +------------>|  Object  |---->|  Object |
                  +----------+     +---------+

Классы waitable objects:

    - Чисто Объекты синхронизации
          (семафоры, мьютесксы итд)
      работа с ними происходит в явном виде

    - События по таймеру
      Как только таймер истекает объект устанавливается

    - Завершения
      (процессы, потоки, jobs, асинхронные операции ввода/вывода)

    - Ожидание ввода
      (каналы, сокеты, cообщения, ввод с консоли)

    - Ожидание изменений
      (например Win32 ожидание изменений для HANDLE полученного
       с помощью FindFirstChangeNotification())

  Mutex

Нить A хочет захватить свободный waitable-mutex:

Что получается в результате

Нить B хочет захватить мьютекс (уже занятый нитью A)

Нить C хочет захватить мьютекс

Нить A особождает мьютекс:

    операции	Win32			UNIX
    ---------------------------------------------------------------
    init		CreateMutex()           pthread_mutex_init()
    open		OpenMutex()
    delete		CloseHandle()		pthread_mutex_destroy()
    trylock					pthread_mutex_trylock()
    lock		WaitForSingleObject()	pthread_mutex_lock()
    unlock		ReleaseMutex()		pthread_mutex_unlock()
    ---------------------------------------------------------------

 Windows

    HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
                 BOOL bInitialOwner,
               LPCTSTR lpName);

    HANDLE OpenMutex(DWORD dwDesiredAccess,
               BOOL bInheritHandle,
               LPCTSTR lpName);

    BOOL ReleaseMutex(HANDLE hMutex);

    DWORD WaitForSingleObject(HANDLE hHandle,
                                  DWORD dwMilliseconds);

Пример использования:

    HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
    if (hMutex == NULL)
    {
        // process errors
    }
    DWORD dwWriteResult = WaitForSingleObject(hMutex, 5000L);
    switch(dwWriteResult)
    {
    case WAIT_OBJECT_0:
            // here is code, which is protected by this mutex
            if (!ReleaseMutex(hMutex))
            {
                // process errors
            }
            break;
    case WAIT_TIMEOUT:
    case WAIT_ABANDONED:
            // we not accqure mutex
    }
    CloseHandle(hMutex);

Дополнительные возможности появляются при использовании Native API

// TODO: check structure names

 Windows

NTSTATUS NTAPI NtCreateMutant(PHANDLE SemaphoreHandle,
            IN ACCESS_MASK DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
            IN BOOLEAN InitialOwner);

NTSTATUS NTAPI NtOpenMutant(OUT PHANDLE hEventHandle,
            IN ACCESS_MASK DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes);

NTSTATUS NTAPI NtReleaseMutant(IN HANDLE MutantHandle,
            OUT PLONG OldOwnedCount OPTIONAL);

NTSTATUS NTAPI NtQueryMutant(IN HANDLE MutantHandle,
            IN MUTANT_INFO_CLASS MutantInformationClass,
            OUT PVOID MutantInformation,
            IN ULONG MutantInformationLength,
            OUT PULONG LengthReturned OPTIONAL);

    typedef enum _MUTANT_INFORMATION_CLASS
    {
        MutantBasicInfo	// 0
    } MUTANT_INFORMATION_CLASS;

typedef struct _MUTANT_BASIC_INFORMATION
{
    LONG	OwnedCount;
    BOOLEAN	Owned;
    BOOLEAN Abandoned;
} MUTANT_BASIC_INFORMATION, * PMUTANT_BASIC_INFORMATION;

 UNIX

// Mutex attributes:

    int	pthread_mutexattr_init
    int	pthread_mutexattr_destroy(pthread_mutexattr_t* attr);
        pthread_mutexattr_set
                          get
                     prioceiling	// priority of mutex owner
                     protocol
                     pshared		// process shared
                     recursive
                     type
    protocol
        PTHREAD_PRIO_INHERIT
        PTHREAD_PRIO_PROTECT
    pshared
        PTHREAD_PROCESS_SHARED
        PTHREAD_PROCESS_PRIVATE
    recursive
        PTHREAD_RECURSIVE_ENABLE
        PTHREAD_RECURSIVE_DISABLE
    type
        PTHREAD_MUTEX_NORMAL
        PTHREAD_MUTEX_ERRORCHECK
        PTHREAD_MUTEX_RECURSIVE

// Mutex:

    int	pthread_mutex_init(pthread_mutex_t* mutex,
                const pthread_mutexattr_t* attr);
    int	pthread_mutex_lock(pthread_mutex_t* mutex);
    int	pthread_mutex_trylock(pthread_mutex_t* mutex);
    int	pthread_mutex_timedlock(pthread_mutex_t* mutex,
                    const struct timespec* abstimeout); // QNX
    int	pthread_mutex_unlock(pthread_mutex_t* mutex);
    int	pthread_mutex_destroy(pthread_mutex_t* mutex);

 Windows

// Windows (Kernel Mode)

typedef struct _FAST_MUTEX
{
#define FM_LOCK_BIT          0x1 // Actual lock bit, 1 = Unlocked, 0 = Locked
#define FM_LOCK_BIT_V        0x0 // Lock bit as a bit number
#define FM_LOCK_WAITER_WOKEN 0x2 // A single waiter has been woken to acquire this lock
#define FM_LOCK_WAITER_INC   0x4 // Increment value to change the waiters count

    volatile LONG Count;
    PKTHREAD      Owner;
    ULONG         Contention;
    KEVENT        Gate;
    ULONG         OldIrql;
} FAST_MUTEX, *PFAST_MUTEX;

VOID     ExInitializeFastMutex(IN PFAST_MUTEX  FastMutex);
VOID     ExAcquireFastMutex(IN PFAST_MUTEX  FastMutex);
BOOLEAN  ExTryToAcquireFastMutex(IN PFAST_MUTEX  FastMutex);
VOID     ExReleaseFastMutex(IN PFAST_MUTEX  FastMutex);

  Semaphore

Как правило не реализованы:

    операции	Win32			UNIX
    ------------------------------------------------------------
    init		CreateSemaphore()       sem_init()
    open		OpenSemaphore()         sem_open()
    delete		CloseHandle()           sem_destroy()/sem_unlink()
    lock		WaitForSingleObject()   sem_wait()
    unlock		ReleaseSemaphore()	sem_post()
    ------------------------------------------------------------

 Windows

    -------------------------------------------------------------------
    HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
                     LONG lInitialCount,
                     LONG lMaximumCount,
                     LPCTSTR lpName);
    -------------------------------------------------------------------
    HANDLE OpenSemaphore(DWORD dwDesiredAccess,
                   BOOL bInheritHandle,
                   LPCTSTR lpName);
    -------------------------------------------------------------------
    BOOL ReleaseSemaphore(HANDLE hSemaphore,
                    LONG lReleaseCount,
                    LPLONG lpPreviousCount);
    -------------------------------------------------------------------

Дополнительная функциональность возможна через Native API:

// TODO: Check structure names

 Windows

NTSTATUS NTAPI NtCreateSemaphore(PHANDLE SemaphoreHandle,
            IN ACCESS_MASK DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
            IN LONG  InitialCount,
            IN LONG  MaximumCount);

NTSTATUS NTAPI NtOpenSemaphore(OUT PHANDLE hEventHandle,
                IN ACCESS_MASK DesiredAccess,
                IN POBJECT_ATTRIBUTES ObjectAttributes);

NTSTATUS NTAPI NtReleaseSemaphore(IN HANDLE SemaphoreHandle,
                  IN LONG ReleaseCount,
                  OUT PLONG PreviousCount OPTIONAL);

NTSTATUS NTAPI NtQuerySemaphore(IN HANDLE SemaphoreHandle,
            IN SEMAPHORE_INFO_CLASS SemaphoreInformationClass, // 0
            OUT PVOID SemaphoreInformation,
            IN ULONG SemaphoreInformationLength,
            OUT PULONG LengthReturned OPTIONAL);

    typedef enum  _SEMAPHORE_INFORMATION_CLASS
    {
        SemaphoreBasicInfo	// 0
    } SEMAPHORE_INFORMATION_CLASS;

    typedef struct _SEMAPHORE_BASIC_INFORMATION
    {
        ULONG  CurrentCount;
        ULONG  MaximumCount;
    } SEMAPORE_BASIC_INFORMATION, * PSEMAPHORE_BASIC_INFORMATION;

Семантика использования:

Wait condition:
    // THREAD 1			// THREAD 2
    while(!expr)			expr = true;
    {                               post(&sem);
        wait(&sem)
    }

Exclusive actions:
    // THREAD 1			// THREAD 2
    wait(&sem);			wait(&sem);
    // critical section             // critical section
    post(&sem);			post(&sem);

Count semaphore:
    // THREAD 1			// THREAD 2
    while(true)			while(true)
    {                               {
        // action               	wait(&sem);
        post(&sem);                     // action
    }                               }

 UNIX

UNIX/QNX
semaphore.h
    int	sem_init(sem_t* sem, int shared, unsigend int value);	// Unnamed
    int	sem_destroy(sem_t* sem);
        sem_open 			// Named (open or create)
        sem_close
    int	sem_wait(sem_t*	sem);
    int	sem_trywait(sem_t* sem);
    int	sem_timedwait(sem_t* sem, const timespec* abstimeout);
    int	sem_post(sem_t* sem);
    int	sem_getvalue(sem_t* sem, int* value);
    int	sem_unlink(const char* name)

  RWLock

Как правило не реализованы:

 UNIX

int   pthread_rwlock_destroy(pthread_rwlock_t *);
int   pthread_rwlock_init(pthread_rwlock_t *,
          const pthread_rwlockattr_t *);
int   pthread_rwlock_rdlock(pthread_rwlock_t *);
int   pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int   pthread_rwlock_trywrlock(pthread_rwlock_t *);
int   pthread_rwlock_unlock(pthread_rwlock_t *);
int   pthread_rwlock_wrlock(pthread_rwlock_t *);

int   pthread_rwlock_timedrdlock(pthread_rwlock_t* rwl,
                const struct timespec* abs)

      pthread_rwlock_timedwrlock

При этом помним про upgrade:  reader to writer, и downgrade: writer to reader.

 Windows

// появились начиная с Windows Vista

typedef struct _RTL_SRWLOCK
{
        PVOID Ptr;
} RTL_SRWLOCK, *PRTL_SRWLOCK;

typedef RTL_SRWLOCK  SRWLOCK,*PSRWLOCK;

#define RTL_SRWLOCK_INIT {0}

VOID    InitializeSRWLock(PSRWLOCK SRWLock);

VOID    AcquireSRWLockShared(PSRWLOCK SRWLock);
VOID    ReleaseSRWLockShared(PSRWLOCK SRWLock);
BOOLEAN TryAcquireSRWLockShared(PSRWLOCK SRWLock);

VOID    AcquireSRWLockExclusive(PSRWLOCK SRWLock);
VOID    ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
BOOLEAN TryAcquireSRWLockExclusive(PSRWLOCK SRWLock);

 Windows

// Windows Kernel Mode

typedef struct _ERESOURCE
{
    LIST_ENTRY SystemResourcesList;
    POWNER_ENTRY OwnerTable;

    //
    // ActiveEntries is the true, 32-bit count.  Existing code
    // checks for ActiveCount == 0, so this toggles between
    // 0 and 1 and back as ActiveEntries goes from 0 to
    // non-zero and back.
    //

    SHORT ActiveCount;
    USHORT Flag;
    volatile PKSEMAPHORE SharedWaiters;
    volatile PKEVENT ExclusiveWaiters;

    //
    // If the resource is owned exclusive, OwnerEntry contains the
    // resource owner.
    //
    // If the resource is owned shared, OwnerEntry may contain one
    // of the shared owners.
    //

    OWNER_ENTRY OwnerEntry;
    ULONG ActiveEntries;
    ULONG ContentionCount;
    ULONG NumberOfSharedWaiters;
    ULONG NumberOfExclusiveWaiters;
    union
    {
        PVOID Address;
        ULONG_PTR CreatorBackTraceIndex;
    };

    KSPIN_LOCK SpinLock;
} ERESOURCE, *PERESOURCE;

BOOLEAN  ExAcquireResourceExclusiveLite(PERESOURCE  Resource, BOOLEAN  Wait);
BOOLEAN  ExAcquireResourceSharedLite(PERESOURCE  Resource, BOOLEAN  Wait);
VOID     ExReleaseResourceLite(PERESOURCE  Resource);

BOOLEAN  ExAcquireSharedStarveExclusive(PERESOURCE  Resource, BOOLEAN  Wait);
BOOLEAN  ExAcquireSharedWaitForExclusive(PERESOURCE  Resource, BOOLEAN  Wait);
VOID     ExConvertExclusiveToSharedLite(PERESOURCE  Resource);
BOOLEAN  ExIsResourceAcquiredExclusiveLite(PERESOURCE  Resource);
ULONG    ExIsResourceAcquiredSharedLite(PERESOURCE  Resource);
ULONG    ExGetExclusiveWaiterCount(PERESOURCE  Resource);
ULONG    ExGetSharedWaiterCount(PERESOURCE  Resource);

  Event

    операции	Win32
    --------------------------------
    init		CreateEvent()
    open		OpenEvent()
    delete		CloseHandle()
    signaled	SetEvent()
            PulseEvent()
    nonsignaled	ResetEvent()
    wait		WaitForSingleObject()
    --------------------------------

 Windows

    -------------------------------------------------------------------
    HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
                 BOOL bManualReset,
                 BOOL bInitialState,
                 LPCTSTR lpName);
    -------------------------------------------------------------------
    HANDLE OpenEvent(DWORD dwDesiredAccess,
               BOOL bInheritHandle,
               LPCTSTR lpName);
    -------------------------------------------------------------------
    BOOL PulseEvent(HANDLE hEvent);
    -------------------------------------------------------------------
    BOOL SetEvent(HANDLE hEvent);
    -------------------------------------------------------------------
    BOOL ResetEvent(HANDLE hEvent);
    -------------------------------------------------------------------

Собственно дополнительная функциональности типа опроса состояния event
доступна в Native API:

// TODO: check true names for structures

 Windows

NTSTATUS NTAPI NtCreateEvent(OUT PHANDLE EventHandle,
            IN ACCESS_MASK DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
            IN EVENT_TYPE EventType,
            IN BOOLEAN  InitialState // TRUE = free
            );

    typedef enum _EVENT_TYPE
    {
        NotificationEvent,	// 0
        SynchronizationEvent	// 1
    } EVENT_TYPE;

NTSTATUS NTAPI  NtOpenEvent(OUT PHANDLE hEventHandle,
            IN ACCESS_MASK DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes);

NTSTATUS  NtClearEvent(IN HANLDE EventHandle);

NTSTATUS NtSetEvent(IN HANDLE EventHandle, IN PBOOLEAN OldState OPTIONAL);
NTSTATUS NtPulseEvent(IN HANDLE EventHandle, IN PBOOLEAN OldState OPTIONAL);
NTSTATUS NtResetEvent(IN HANDLE EventHandle, IN PBOOLEAN OldState OPTIONAL);

NTSTATUS NTAPI  NtQueryEvent(IN HANDLE EventHandle,
            IN EVENT_INFO_CLASS EventInformationClass,	// 0
            OUT PVOID  EventInformation,
            IN ULONG EventInformationLength
            OUT PULONG LengthReturned OPTIONAL);

    typedef struct _EVENT_BASIC_INFORMATION
    {
        EVENT_TYPE  EventType;
        LONG	    SignalState;
    } EVENT_INFO, *PEVENT_INFO;

    typedef enum _EVENT_INFORMATION_CLASS
    {
           EventInfo	// 0
    } EVENT_INFORMATION_CLASS;

  Event pair

Пара событий. Называются High и Low. Оптимизированны под высокоскоростные
взаимодействия client/server. (Сейчас используются мало - заменило LPC.

 Windows

NTSTATUS NTAPI NtCreateEventPair(OUT PHANDLE hEventPair,
            IN ACCESS_MASK AcccessMask,
            IN POBJECT_ATTRIBUTES  ObjectAttributes);

NTSTATUS NTAPI NtOpenEventPair(OUT PHANDLE hEventPair,
            IN ACCESS_MASK AccessMask,
            IN POBJECT_ATTRIBUTES  ObjectAttributes);

NTSTATUS NTAPI NtWaitLowEventPair(IN HANDLE hEventPair);
NTSTATUS NTAPI NtWaitHighEventPair(IN HANDLE hEvent Pair);

NTSTATUS NTAPI NtSetLowEventPair(IN HANDLE hEventPair);
NTSTATUS NTAPI NtSetHighEventPair(IN HANDLE hEventPair);

NTSTATUS NTAPI NtSetLowWaitHighEventPair(IN HANDLE hEventPair);
NTSTATUS NTAPI NtSetHighWaitLowEventPair(IN HANDLE hEventPair);

  Conditional vars

Смысл conditional vars:
    обеспечить возможность ожидания conditional var внутри кода залоченного
    мьютексом.
    Если внутри такой критической секции цсловие ожидания не выполняется то
    мьютекс отпускается, ждеться условие, затем мьютекс снова захватывается
    и продолжается выполнение.
    (При этом если пришли сигналы в процессе ожидания условной переменной,
     то они обрабатываются со снятым mutexoм.

    pthread_mutex_lock(&mutex);		Lock Mutex
    ....					Critical section code
    pthread_cond_wait(&cvar, &mutex);	Let: Condition is true
                            Do nothing
    ...					Critical section code
    pthread_mutex_unlock(&mutex);		Unlock mutex

    pthread_mutex_lock(&mutex);		Lock Mutex
    ....					Critical section code
    pthread_cond_wait(&cvar, &mutex);	Let: Condition is false
                            Unlock Mutex
                            Wait for condition
                            Lock Mutex
    ...					Critical section code
    pthread_mutex_unlock(&mutex);		Unlock mutex

    -------------------------------------------------------------------
    int   pthread_cond_init(pthread_cond_t *,
                const pthread_condattr_t *);
    -------------------------------------------------------------------
    int   pthread_cond_destroy(pthread_cond_t *);
    -------------------------------------------------------------------
    int   pthread_cond_signal(pthread_cond_t *);
    -------------------------------------------------------------------
    int   pthread_cond_broadcast(pthread_cond_t *);
    -------------------------------------------------------------------
    int   pthread_cond_wait(pthread_cond_t *,
                pthread_mutex_t *);
    -------------------------------------------------------------------
    int   pthread_cond_timedwait(pthread_cond_t *,
                           pthread_mutex_t *,
                     const struct timespec *);
    -------------------------------------------------------------------

Condition variables

 UNIX

    int	pthread_condattr_init(pthread_condattr_t* attr)
    int	pthread_condattr_destroy(pthread_condattr_t* attr);

    int	pthread_condattr_set
                 get
                    pshared
                    clock	// select timer

    int	pthread_cond_init(pthread_cond_t* cond,
                 pthread_condattr_t* attr);

    int	pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
            // block on cond, unlock mutex
    int	pthread_cond_timedwait(pthread_cond_t* cond,
                    pthread_mutex_t* mutex,
                    const struct timespsec* abstime); // QNX

    int	pthread_cond_signal(pthread_cond_t* conde)
            // one thread, then thread try to lock it mutex
    int	pthread_cond_broadcast(pthread_cond_t* cond);
            // all

    int	pthread_cond_destroy(pthread_cond_t* cond);

 Windows

// Появились начиная с Vista

typedef struct _RTL_CONDITION_VARIABLE
{
        PVOID Ptr;
} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;

typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITIONAL_VARIABLE;
#define RTL_CONDITION_VARIABLE_INIT {0}

VOID	InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
BOOL 	SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable,
                   PCRITICAL_SECTION CriticalSection,
                   DWORD dwMilliseconds);
BOOL    SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable,
                  PSRWLOCK SRWLock,
                  DWORD dwMilliseconds,
                  ULONG Flags);
    // Flags is: CONDITION_VARIABLE_LOCKMODE_SHARED, otherwise exclusive

VOID 	WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
VOID 	WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable);

  Таймеры

THIS SECTION IS UNDER CONSTRUCTION

 Windows

VOID  WINAPI Sleep(DWORD dwMilliseconds);
DWORD WINAPI SleepEx(DWORD dwMilliseconds, BOOL bAlertable);

 Windows

HANDLE WINAPI CreateWaitableTimer(LPSECURITY_ATTRIBUTES lpTimerAttributes,
                  BOOL bManualReset,
                  LPCTSTR lpTimerName);

HANDLE WINAPI CreateWaitableTimerEx(LPSECURITY_ATTRIBUTES lpTimerAttributes,	// Vista
                    LPCTSTR lpTimerName,
                    DWORD dwFlags,
                    DWORD dwDesiredAccess);

    // Flags is: CREATE_WAITABLE_TIMER_MANUAL_RESET

HANDLE WINAPI OpenWaitableTimer(DWORD dwDesiredAccess,
                 BOOL bInheritHandle,
                LPCTSTR lpTimerName);

BOOL WINAPI SetWaitableTimer(HANDLE hTimer,
                   const LARGE_INTEGER *pDueTime,
                   LONG lPeriod,
                   PTIMERAPCROUTINE pfnCompletionRoutine,
                   LPVOID lpArgToCompletionRoutine,
                   BOOL fResume);

BOOL WINAPI SetWaitableTimerEx(HANDLE hTimer, 		// Windows 7
                   const LARGE_INTEGER *lpDueTime,
                   LONG lPeriod,
                   PTIMERAPCROUTINE pfnCompletionRoutine,
                   LPVOID lpArgToCompletionRoutine,
                   PREASON_CONTEXT WakeContext,
                   ULONG TolerableDelay);

BOOL WINAPI CancelWaitableTimer(HANDLE hTimer);

VOID CALLBACK TimerAPCProc(LPVOID lpArgToCompletionRoutine,
                 DWORD dwTimerLowValue,
                 DWORD dwTimerHighValue);

  Критические секции

    Критическая секция - кусок кода который будет выполняться без вытеснения

Собственно критическая секция в простом варианте:

    waitable_mutex_lock(&mutex);
    // Here is critical section itself
    waitable_mutex_unlock(&mutex);

 Windows

typedef struct _RTL_CRITICAL_SECTION
{
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

    //
    //  The following three fields control entering and exiting the critical
    //  section for the resource
    //

    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;        // from the thread's ClientId->UniqueThread
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

typedef RTL_CRITICAL_SECTION CRITICAL_SECTION, *LPCRITICAL_SECTION;

    void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
    BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
    void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
    void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
    void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

Реально критическая секция не сразу блокируется на мютексе, а пытается сначала некоторое
количество попыток захватить spin-lock.

Если нить умерает то критическая секция оказывается в abandoned-state, и никакая нить
не может в нее войти.
(с мьютексами такого не возникает - потому что mutex - объект ядра и его освобождают
в таком случае).

    BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,
                            DWORD dwSpinCount);

    DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection,
                       DWORD dwSpinCount);

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

Критическая секция без защиты от прерывания:

    System_Variable_Enable_switch_process = NO;

Критическая секция с защитой от прерывания

    Disable_interrupt

Но такие вещи надо делать на реально короткий промежуток времени.

  барьеры

 Windows

// Sample implementation
LockFree barrier:
    if (InterlockedIncrement(&ActiveThreads) == MaxThreads)
    {
        SetEvent(StartEvent);
    } else {
        WaitForSingleObject(StartEvent, INFINIFY);
    }

 UNIX

    int	pthread_barrier_init(pthread_barrier_t* barrier,
                     const pthread_barrierattr_t* attr,
                     unsigned int count);

    int	pthread_barrier_destroy(pthread_barrier_t* barrier);
    int	pthread_barrier_wait(pthread_barrier_t* barrier);
        // return for first threads: BARRIER_SERIAL_THREAD
        //	  for other threads: 0

    int	pthread_barrierattr_init(pthread_barrierattr_t* attr);
    int	pthread_barrierattr_destroy(pthread_barrierattr_t* attr);
    int	pthread_barrierattr_setpshared(pthread_barrierattr_t* attr, int pshared);
    int	pthread_barrierattr_getpshared(pthread_barrierattr_t* attr, int* pshared);

// Example of internal structure of Barrier in QNX 6.5

    typedef struct
    {
        unsigned int 	barrier;
        unsigned int    count;
        pthread_mutex_t	lock;
        pthread_cond_t	bcond;
    } pthread_barrier_t;

  Реентерабильные семафоры и мьютексы

Реентерабильные - позволяют делать многократный захват из
одной и той же нити.

Как делать реентерабельные мьютексы из нереентерабильных?

Нужна структура которая содержит информацию о реентерабильном
мьютексе, а также простой мьютекс которым защищена эта
структура:

    +----------------+
    |   Thread ID    |
    +----------------+
    |   Lock Count   |
    +----------------+
    |     Mutex      |
    +----------------+

bool	trylock_reenterable_mutex(reenter_mutex remutex)
{
    if (trylock_mutex(remutex.mutex) == false)
    {
        return false;
    }
    if (remutex.lockcount != 0)
    {
        if (remutex.threadid == CurrentThreadId())
        {
            remutex.lockcount++;
            unlock_mutex(remutex.mutex)
            return	true;
        } else {
            unlock_mutex(remutex.mutex)
            return	false;	// Busy by other thread
        }
    } else {
        remutex.threaid = CurrentThreadId();
        remutex.lockcount++;
        unlock_mutex(remutex.mutex);
        return	true;
    }
}

bool	unlock_reenterable_mutex(reenter_mutex remutex)
{
    lock_mutex(remutex.mutex);
    if (remutex.lockcount == 0)
    {
        unlock_mutex(remutex.mutex);
        return	false;		// Mutex already free
    }
    if (remutex.threadid != CurrentThreadId())
    {
        unlock_mutex(remutex.mutex);
        return	false;		// Try to unlock in wrong thread
    }
    remutex.lockcount--;
    unlock_mutex(remutex.mutex);
    return	true;			// Success
}

  Queued-mutex

Основная идея:
    в обычном мьютексе все долбяться чтобы получить доступ, а мьютекс занят
    достаточно долго. В queued-mutex долбяться что бы получить доступ к очереди,
    а это гораздо быстрее.

                     que[MAX]
    +--------+	+-------+
    | amutex |      | que[0]|
    +--------+      +-------+
    | current|      | que[1]|
    +--------+      +-------+
    |  next  |      |  ...  |
    +--------+      +-------+
                | que[N]|
            +-------+

bool	lock_queued_mutex(queued_mutex mutex)
{
    lock_mutex(amutex);
    if (next == current) return ERROR_CAPACITY_OF_QUEUED_MUTEX_EXCEEDED;
    address = &que[next];
    next++;
    if (next >= MAX) next = 0;
    unlock_mutex(amutex);
    while(*address == UNLOCKED) ;	// читает только из cache
    return	SUCCESS;
}

bool	unlock_queued_mutex(queued_mutex mutex)
{
    lock_mutex(amutex);
    que[current] = UNLOCKED;
    current++;
    if (current >= MAX) current = 0;
    que[current] = LOCKED;
    unlock_mutex(amutex);
}

примеры (Windows Kernel Mode):

VOID	KeAcquireInStackQueuedSpinLock(PKSPIN_LOCK SpinLock, PKLOCK_QUEUE_HANDLE LockHandle);
VOID	KeReleaseInStackQueuedSpinLock(PKLOCK_QUEUE_HANDLE LockHandle);

    struct KSPIN_LOCK_QUEUE
    {
        struct KSPIN_LOCK_QUEUE * volatile Next;
        PKSPIN_LOCK	          volatile Lock;
    };

    struct KLOCK_QUEUE_HANDLE
    {
        KSPIN_LOCK_QUEUE	LockQueue;
        KIRQL			OldIrql;
    };

  C++ Wrappers

Примеры C++ wrappers вокруг синхронизационных объектов на примере Qt.
Обратите внимание на Loker классы - они удобны для автоматического захвата/освобождения
ресурсов.

class QMutex
{
public:
    QMutex(bool recursive = FALSE);
    virtual ~QMutex();
    void	lock();
    void	unlock();
    bool	locked();
    bool	trylock();
};

class QMutexLocker
{
public:
    QMutexLocker(QMutex* mutex);	// Lock on create
    ~QMutexLocker();		// if locked, unlock on destroy

    QMutex* mutex() const;
    void	relock();
    void	unlock();
};

class QReadWriteLock
{
public:
    QReadWriteLock();
    ~QReadWriteLock();
    void	lockForRead();
    void	lockForWrite();
    bool	tryLockForRead();
    bool	tryLockForWrite();
    void	unlock();
};

class QReadLocker
{
public:
    QReadLocker(QReadWriteLock* lock);
    ~QReadLocker();

    QReadWriteLock* readWriteLock() const;
    void	relock();
    void	unlock();
};

class QWriteLocker
{
public:
    QWriteLocker(QReadWriteLock* lock);
    ~QWriteLocker();

    QReadWriteLock* readWriteLock() const;
    void  relock();
    void  unlock();
};

class QSemaphore
{
public:
    QSemaphore(int n = 0);
    ~QSemaphore();
    void	acquire(int n = 1);
    int	available() const;
    void	release(int n = 1);
    bool	tryAcquire(int n = 1);
};

class QWaitCondition
{
public:
    QWaitCondition();
    ~QWaitCondition();

    bool	wait(QMutex* mutex, unsigned long time = ULONG_MAX);
    void	wakeAll();
    void	wakeOne();
};


82.2. ПРОБЛЕМЫ СИНХРОНИЗАЦИИ

  Deadlocks

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

Deadlocks

    Процессом P1 захвачен ресурс M1
    Процессом P2 захвачен ресурс М2

        P1: OWN:  M1
        P1: WAIT: --

        P2: OWN:  M2
        P2: WAIT: --

    Процесс P1 хочет захватить ресурс М2
    Система смотрит зависимости:
        M2 -(owner)- P2 -(wait) - NONE
    Система ставит P1 ждать

        P1: OWN:  M1
        P1: WAIT: M2

        P2: OWN:  M2
        P2: WAIT: --

    Процесс P2 хочет захватить ресурс M1
    Система смотрит дерево зависимостей
        M1 -(owner)- P1 -(wait)- M2 -(owner)- CURRENT_PROCESS
    Вот он - DEADLOCK
    Типичное действие операционной системы не дать делать этот Wait
    процессу P2, и еще выбить процесс P1 из его ожидания M2,
        со статусом - типа deadlock

  LiveLock

  Lost Wakeup


82.3. СТАНДАРТНЫЕ БИБЛИОТЕКИ ДЛЯ СИНХРОНИЗАЦИИ

  Атомарные операции

// новый стандарт C++

namespace std
{
    enum memory_order;
    template  T kill_dependency(T y);

#define ATOMIC_INTEGRAL_LOCK_FREE unspecified
#define ATOMIC_ADDRESS_LOCK_FREE unspecified

    struct atomic_flag;
    bool atomic_flag_test_and_set(volatile atomic_flag*);
    bool atomic_flag_test_and_set(atomic_flag*);
    bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order);
    bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order);
    void atomic_flag_clear(volatile atomic_flag*);
    void atomic_flag_clear(atomic_flag*);
    void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order);
    void atomic_flag_clear_explicit(atomic_flag*, memory_order);

#define ATOMIC_FLAG_INIT unspecified

    struct atomic_bool;

    bool atomic_is_lock_free(const volatile atomic_bool*);
    bool atomic_is_lock_free(const atomic_bool*);
    void atomic_store(volatile atomic_bool*, bool);
    void atomic_store(atomic_bool*, bool);
    void atomic_store_explicit(volatile atomic_bool*, bool, memory_order);
    void atomic_store_explicit(atomic_bool*, bool, memory_order);
    bool atomic_load(const volatile atomic_bool*);
    bool atomic_load(const atomic_bool*);
    bool atomic_load_explicit(const volatile atomic_bool*, memory_order);
    bool atomic_load_explicit(const atomic_bool*, memory_order);
    bool atomic_exchange(volatile atomic_bool*, bool);
    bool atomic_exchange(atomic_bool*, bool);
    bool atomic_exchange_explicit(volatile atomic_bool*, bool, memory_order);
    bool atomic_exchange_explicit(atomic_bool*, bool, memory_order);
    bool atomic_compare_exchange_weak(volatile atomic_bool*, bool*, bool);
    bool atomic_compare_exchange_weak(atomic_bool*, bool*, bool);
    bool atomic_compare_exchange_strong(volatile atomic_bool*, bool*, bool);
    bool atomic_compare_exchange_strong(atomic_bool*, bool*, bool);
    bool atomic_compare_exchange_weak_explicit(volatile atomic_bool*, bool*, bool,
                memory_order, memory_order);
    bool atomic_compare_exchange_weak_explicit(atomic_bool*, bool*, bool,
                memory_order, memory_order);
    bool atomic_compare_exchange_strong_explicit(volatile atomic_bool*, bool*, bool,
                memory_order, memory_order);
    bool atomic_compare_exchange_strong_explicit(atomic_bool*, bool*, bool,
                memory_order, memory_order);

    struct atomic_itype;

    bool atomic_is_lock_free(const volatile atomic_itype*);
    bool atomic_is_lock_free(const atomic_itype*);
    void atomic_store(volatile atomic_itype*, integral);
    void atomic_store(atomic_itype*, integral);
    void atomic_store_explicit(volatile atomic_itype*, integral,
                memory_order);
    void atomic_store_explicit(atomic_itype*, integral,
                memory_order);

    integral atomic_load(const volatile atomic_itype*);
    integral atomic_load(const atomic_itype*);
    integral atomic_load_explicit(const volatile atomic_itype*, memory_order);
    integral atomic_load_explicit(const atomic_itype*, memory_order);
    integral atomic_exchange(volatile atomic_itype*, integral);
    integral atomic_exchange(atomic_itype*, integral);
    integral atomic_exchange_explicit(volatile atomic_itype*, integral,
                memory_order);
    integral atomic_exchange_explicit(atomic_itype*, integral,
                memory_order);
    bool atomic_compare_exchange_weak(volatile atomic_itype*, integral*, integral);
    bool atomic_compare_exchange_weak(atomic_itype*, integral*, integral);
    bool atomic_compare_exchange_strong(atomic_itype*, integral*, integral);
    bool atomic_compare_exchange_weak_explicit(volatile atomic_itype*, integral*,
                integral, memory_order, memory_order);
    bool atomic_compare_exchange_weak_explicit(atomic_itype*, integral*,
                integral, memory_order, memory_order);
    bool atomic_compare_exchange_strong_explicit(volatile atomic_itype*, integral*,
                integral, memory_order, memory_order);

    bool atomic_compare_exchange_strong_explicit(atomic_itype*, integral*,
                integral, memory_order, memory_order);
    integral atomic_fetch_add(atomic_itype*, integral);
    integral atomic_fetch_add_explicit(volatile atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_add_explicit(atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_sub(volatile atomic_itype*, integral);
    integral atomic_fetch_sub(atomic_itype*, integral);
    integral atomic_fetch_sub_explicit(volatile atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_sub_explicit(atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_and(volatile atomic_itype*, integral);
    integral atomic_fetch_and(atomic_itype*, integral);
    integral atomic_fetch_and_explicit(volatile atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_and_explicit(atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_or(volatile atomic_itype*, integral);
    integral atomic_fetch_or(volatile atomic_itype*, integral);
    integral atomic_fetch_or_explicit(volatile atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_or_explicit(atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_xor(volatile atomic_itype*, integral);
    integral atomic_fetch_xor(atomic_itype*, integral);
    integral atomic_fetch_xor_explicit(volatile atomic_itype*, integral,
                memory_order);
    integral atomic_fetch_xor_explicit(atomic_itype*, integral,
                memory_order);

    struct atomic_address;
    bool atomic_is_lock_free(const volatile atomic_address*);
    bool atomic_is_lock_free(const atomic_address*);
    void atomic_store(volatile atomic_address*, void*);
    void atomic_store(atomic_address*, void*);
    void atomic_store_explicit(volatile atomic_address*, void*, memory_order);
    void atomic_store_explicit(atomic_address*, void*, memory_order);
    void* atomic_load(const volatile atomic_address*);
    void* atomic_load(const atomic_address*);
    void* atomic_load_explicit(const volatile atomic_address*, memory_order);
    void* atomic_load_explicit(const atomic_address*, memory_order);
    void* atomic_exchange(volatile atomic_address*, void*);
    void* atomic_exchange(atomic_address*, void*);
    void* atomic_exchange_explicit(volatile atomic_address*, void*, memory_order);
    void* atomic_exchange_explicit(atomic_address*, void*, memory_order);
    bool atomic_compare_exchange_weak(volatile atomic_address*, void**, void*);
    bool atomic_compare_exchange_weak(atomic_address*, void**, void*);
    bool atomic_compare_exchange_strong(volatile atomic_address*, void**, void*);
    bool atomic_compare_exchange_strong(atomic_address*, void**, void*);
    bool atomic_compare_exchange_weak_explicit(volatile atomic_address*, void**, void*,
            memory_order, memory_order);
    bool atomic_compare_exchange_weak_explicit(atomic_address*, void**, void*,
            memory_order, memory_order);
    bool atomic_compare_exchange_strong_explicit(atomic_address*, void**, void*,
            memory_order, memory_order);
    void* atomic_fetch_add(volatile atomic_address*, ptrdiff_t);
    void* atomic_fetch_add(atomic_address*, ptrdiff_t);
    void* atomic_fetch_add_explicit(volatile atomic_address*, ptrdiff_t,
            memory_order);
    void* atomic_fetch_add_explicit(atomic_address*, ptrdiff_t,
            memory_order);
    void* atomic_fetch_sub(volatile atomic_address*, ptrdiff_t);
    void* atomic_fetch_sub(atomic_address*, ptrdiff_t);
    void* atomic_fetch_sub_explicit(volatile atomic_address*, ptrdiff_t,
            memory_order);
    void* atomic_fetch_sub_explicit(atomic_address*, ptrdiff_t,
            memory_order);

    template struct atomic;
    template struct atomic;
    template<> struct atomic;

    void atomic_thread_fence(memory_order);
    void atomic_signal_fence(memory_order);
}

namespace std
{
    typedef enum memory_order
    {
        memory_order_relaxed,
        memory_order_consume,
        memory_order_acquire,
        memory_order_release,
        memory_order_acq_rel,
        memory_order_seq_cst
    } memory_order;
}

  Синхронизационные примитивы

// новый стандарт C++

namespace std
{
    class mutex;
    class recursive_mutex;
    class timed_mutex;
    class recursive_timed_mutex;

    struct defer_lock_t { };
    struct try_to_lock_t { };
    struct adopt_lock_t { };
    constexpr defer_lock_t defer_lock () { };
    constexpr try_to_lock_t try_to_lock () { };
    constexpr adopt_lock_t adopt_lock () { };

    template  class lock_guard;
    template  class unique_lock;
    template

    void swap(unique_lock& x, unique_lock& y);
    template  int try_lock(L1&, L2&, L3&...);
    template  void lock(L1&, L2&, L3&...);

    struct once_flag
    {
        constexpr once_flag();
        once_flag(const once_flag&) = delete;
        once_flag& operator=(const once_flag&) = delete;
    };

    template
        void call_once(once_flag& flag, Callable func, Args&&... args);
}

namespace std
{
    class mutex
    {
    public:
        constexpr mutex();
        ~mutex();
        mutex(const mutex&) = delete;
        mutex& operator=(const mutex&) = delete;
        void lock();
        bool try_lock();
        void unlock();

        typedef implementation-defined native_handle_type;
        native_handle_type native_handle();
    };
}

namespace std
{
    class recursive_mutex
    {
    public:
        recursive_mutex();
        ~recursive_mutex();
        recursive_mutex(const recursive_mutex&) = delete;
        recursive_mutex& operator=(const recursive_mutex&) = delete;
        void lock();
        bool try_lock();
        void unlock();

        typedef implementation-defined native_handle_type;
        native_handle_type native_handle();
    };
}

namespace std
{
    class timed_mutex
    {
    public:
        timed_mutex();
        ~timed_mutex();
        timed_mutex(const timed_mutex&) = delete;
        timed_mutex& operator=(const timed_mutex&) = delete;
        void lock();
        bool try_lock();
        template
          bool try_lock_for(const chrono::duration& rel_time);
        template
          bool try_lock_until(const chrono::time_point& abs_time);
        void unlock();

        typedef implementation-defined native_handle_type;
        native_handle_type native_handle();
    };
}

namespace std
{
    class recursive_timed_mutex
    {
    public:
        recursive_timed_mutex();
        ~recursive_timed_mutex();
        recursive_timed_mutex(const recursive_timed_mutex&) = delete;
        recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
        void lock();
        bool try_lock();
        template
          bool try_lock_for(const chrono::duration& rel_time);
        template
          bool try_lock_until(const chrono::time_point& abs_time);
        void unlock();

    typedef implementation-defined native_handle_type;
    native_handle_type native_handle();
    };
}

namespace std
{
    struct defer_lock_t { }; // do not acquire ownership of the mutex
    struct try_to_lock_t { };// try to acquire ownership of the mutex
                 // without blocking
    struct adopt_lock_t { }; // assume the calling thread has already
                 // obtained mutex ownership and manage it
    extern const defer_lock_t defer_lock { };
    extern const try_to_lock_t try_to_lock{ };
    extern const adopt_lock_t adopt_lock{ };
}

namespace std
{
    template  class lock_guard
    {
    public:
        typedef Mutex mutex_type;
        explicit lock_guard(mutex_type& m);
        lock_guard(mutex_type& m, adopt_lock_t);
        ~lock_guard();
        lock_guard(lock_guard const&) = delete;
        lock_guard& operator=(lock_guard const&) = delete;
    private:
        mutex_type& pm; // exposition only
    };
}

namespace std
{
    template  class unique_lock
    {
    public:
        typedef Mutex mutex_type;

        unique_lock();
        explicit unique_lock(mutex_type& m);
        unique_lock(mutex_type& m, defer_lock_t);
        unique_lock(mutex_type& m, try_to_lock_t);
        unique_lock(mutex_type& m, adopt_lock_t);
        template
          unique_lock(mutex_type& m,
                  const chrono::time_point& abs_time);
        template
          unique_lock(mutex_type& m, const chrono::duration& rel_time);
        ~unique_lock();
        unique_lock(unique_lock const&) = delete;
        unique_lock& operator=(unique_lock const&) = delete;
        unique_lock(unique_lock&& u);
        unique_lock& operator=(unique_lock&& u);
        void lock();
        bool try_lock();
        template
          bool try_lock_for(const chrono::duration& rel_time);
        template
          bool try_lock_until(const chrono::time_point& abs_time);
        void unlock();

        void swap(unique_lock& u);
        mutex_type *release();

        bool owns_lock() const;
        explicit operator bool () const;
        mutex_type* mutex() const;
    private:
        mutex_type *pm; // exposition only
        bool owns; // exposition only
    };

    template
      void swap(unique_lock& x, unique_lock& y);
}

namespace std
{
    class condition_variable;
    class condition_variable_any;
    enum class cv_status
    {
        no_timeout,
        timeout
    };
}

namespace std
{
    class condition_variable
    {
    public:
        condition_variable();
        ~condition_variable();
        condition_variable(const condition_variable&) = delete;
        condition_variable& operator=(const condition_variable&) = delete;
        void notify_one();
        void notify_all();
        void wait(unique_lock& lock);
        template
          void wait(unique_lock& lock, Predicate pred);
        template
          bool cv_status wait_until(unique_lock& lock,
                          const chrono::time_point& abs_time);
        template
           bool wait_until(unique_lock& lock,
                    const chrono::time_point& abs_time,
                    Predicate pred);

        template
            bool cv_status wait_for(unique_lock& lock,
                    const chrono::duration& rel_time);
        template
            bool wait_for(unique_lock& lock,
                const chrono::duration& rel_time,
            Predicate pred);

        typedef implementation-defined native_handle_type;
        native_handle_type native_handle();
    };
}

namespace std
{
    class condition_variable_any
    {
    public:
        condition_variable_any();
        ~condition_variable_any();
        condition_variable_any(const condition_variable_any&) = delete;
        condition_variable_any& operator=(const condition_variable_any&) = delete;
        void notify_one();
        void notify_all();
        template  void wait(Lock& lock);
        template  void wait(Lock& lock, Predicate pred);
        template
            bool cv_status wait_until(Lock& lock,
                const chrono::time_point& abs_time);
        template
            bool wait_until(Lock& lock,
            const chrono::time_point& abs_time, Predicate pred);
        template
            bool cv_status wait_for(Lock& lock,
                const chrono::duration& rel_time);
        template
            bool wait_for(Lock& lock,
                const chrono::duration& rel_time, Predicate pred);

        typedef implementation-defined native_handle_type;
        native_handle_type native_handle();
    };
}

  MFC

class CSyncObject : public CObject
{
    DECLARE_DYNAMIC(CSyncObject)

public:
    CSyncObject(LPCTSTR pstrName);

public:
    operator HANDLE() const;
    HANDLE  m_hObject;

    virtual BOOL Lock(DWORD dwTimeout = INFINITE);
    virtual BOOL Unlock() = 0;
    virtual BOOL Unlock(LONG /* lCount */, LPLONG /* lpPrevCount=NULL */)
        { return TRUE; }

public:
    virtual ~CSyncObject();
    friend class CSingleLock;
    friend class CMultiLock;
};

class CSemaphore : public CSyncObject
{
    DECLARE_DYNAMIC(CSemaphore)

public:
    CSemaphore(LONG lInitialCount = 1, LONG lMaxCount = 1,
        LPCTSTR pstrName=NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL);

public:
    virtual ~CSemaphore();
    virtual BOOL Unlock();
    virtual BOOL Unlock(LONG lCount, LPLONG lprevCount = NULL);
};

class CMutex : public CSyncObject
{
    DECLARE_DYNAMIC(CMutex)

public:
    CMutex(BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL,
        LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);

public:
    virtual ~CMutex();
    BOOL Unlock();
};

class CEvent : public CSyncObject
{
    DECLARE_DYNAMIC(CEvent)

public:
    CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE,
        LPCTSTR lpszNAme = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);

public:
    BOOL SetEvent();
    BOOL PulseEvent();
    BOOL ResetEvent();
    BOOL Unlock();

public:
    virtual ~CEvent();
};

class CCriticalSection : public CSyncObject
{
    DECLARE_DYNAMIC(CCriticalSection)

public:
    CCriticalSection();

public:
    operator CRITICAL_SECTION*();
    CRITICAL_SECTION m_sect;

public:
    BOOL Unlock();
    BOOL Lock();
    BOOL Lock(DWORD dwTimeout);

public:
    virtual ~CCriticalSection();
};

class CSingleLock
{
public:
    CSingleLock(CSyncObject* pObject, BOOL bInitialLock = FALSE);

public:
    BOOL Lock(DWORD dwTimeOut = INFINITE);
    BOOL Unlock();
    BOOL Unlock(LONG lCount, LPLONG lPrevCount = NULL);
    BOOL IsLocked();

public:
    ~CSingleLock();

protected:
    CSyncObject* m_pObject;
    HANDLE  m_hObject;
    BOOL    m_bAcquired;
};

class CMultiLock
{
public:
    CMultiLock(CSyncObject* ppObjects[], DWORD dwCount, BOOL bInitialLock = FALSE);

public:
    DWORD Lock(DWORD dwTimeOut = INFINITE, BOOL bWaitForAll = TRUE,
        DWORD dwWakeMask = 0);
    BOOL Unlock();
    BOOL Unlock(LONG lCount, LPLONG lPrevCount = NULL);
    BOOL IsLocked(DWORD dwItem);

public:
    ~CMultiLock();

protected:
    HANDLE  m_hPreallocated[8];
    BOOL    m_bPreallocated[8];

    CSyncObject* const * m_ppObjectArray;
    HANDLE* m_pHandleArray;
    BOOL*   m_bLockedArray;
    DWORD   m_dwCount;
};


83. MIDDLEWARE

THIS SECTION IS UNDER CONSTRUCTION

Эта секция посвещена Middleware - прослойке между компонентами в
гетерогенной Enterprise сети.

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

Собственно уровни middleware:
    - Transaction
    - Request/Reply  (RPC)
    - Message Parsing

  Проблематика

Distributed system:
    Concurrency
    Independed failure
    No global time
    Communication delay
    Incosistance state

  Отказы

  Группы

  Транспорт

MOM (Message Oriented Middleware)

Гарантированная доставка
    Хранение
    Проигрование
    Кэширование сообщений

    Подписка (Publish/Subscribe)

Посылка сообщений
    синхронная
    асинхронная

Распространение сообщений
    Unicast/Broadcast/Multicast
    Топология сети по которой передаются сообщения
    Spanned tree
        с заданным корнем
        без заданного корня
    Flooding problems
    Dynamic routings (востановление при сбоях)

    single source FIFO ordering
    casually ordering
    etc

    Buffered Message Passing
    Unbuffered Message Passing

    Message passing semantics
        at-least-once
        exactly once

    peer group
    client-server group
    diffusion group		(message send to all clients and servers)
    hierarchical group

    Group membership discovery/advertizing

    Write-update
    Write-invalidate

    Unbound
    Bound-to-host
    Bound-to-server

    Delivery Semantics
        Single 	(to one of members)
        K-delivery (to K members)
        Quorum (to quorum number of members)
        Atomic (all current members receive or none)
    Response Semantics
        No responses
        Single response
        Majority response
        Total response

    Message ordering
        No ordering
        FIFO ordering
        Causal ordering
        Total ordering

    Multicast problems
        lost message
        fail stop

    Total ordered multicast, based on logical ring

    Securing

Reliability
    Integrity
    No Duplicates
    Nonfaulty Liveness
        посылаем broadcast - все получили
    Faulty Liveness

Leader Election
    например того у кого будем получать сообщения

TODO: Producer/Consumers queues with synchronization
    Sequentially consistent shared memory

Time managements
    время идет на каждой ноде по разному
    использование времени
        physical clocks
        logical clocks (of processor)
        vector clocks
    синхронизация времени

Fault-toulerant consensus

    Messages
    RPC
    Distributed Objects (DCOM, CORBA)

Clusters
Grid computing
    Load Balancing and Scheduling

Common problems
    Endian


84. СЕТЕВЫЕ ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

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

Собственно сама сетевая подсистема рассмотрена в секциях
    55.9. СЕТИ
    81.4. СЕТЕВАЯ ПОДСИСТЕМА


84.1. ПРОТОКОЛЫ СЕТЕВОЙ ИНФРАСТРУКТУРЫ

THIS SECTION IS UNDER CONSTRUCTION


84.1.1. РАЗРЕШЕНИЕ ЛОКАЛЬНЫХ АДРЕССОВ

THIS SECTION IS UNDER CONSTRUCTION

  ARP

ARP (Address Resolution Protocol)

Смотрите для начала секцию:
    55.9.3.1. РАЗРЕШЕНИЕ АДРЕССОВ В ЛОКАЛЬНОМ СЕГМЕНТЕ СЕТИ

ARP Request:
-------- Packet -----------, len = 003C
              Ethernet Frame Type: Ethernet II
00000000 : dump  (0006)  Destination Address
00000000 :  FF FF FF FF FF FF                                [......----------]
00000006 : dump  (0006)  Source Address
00000006 :  00 80 AD B8 2C 82                                [._?,'----------]
0000000C : word      0806 Protocol
              Protocol: ARP
- - - - - - - - ARP/RARP - - - - - -
0000000E : word      0001 Type of Hardware
            * Ethernet
00000010 : word      0800 Type of Protocol
            * IPv4
00000012 : byte        06 Hardware Address Length
00000013 : byte        04 Protocol Address Length
00000014 : word      0001 Operation
            * ARP Request
00000016 : dump  (0006)  Sender Hardware Address
00000016 :  00 80 AD B8 2C 82                                [._?,'----------]
0000001C : dump  (0004)  Sender Protocol Address
0000001C :  D4 2E 03 21                                      [?..!------------]
00000020 : dump  (0006)  Target Hardware Address
00000020 :  00 00 00 00 00 00                                [......----------]
00000026 : dump  (0004)  Target Protocol Address
00000026 :  D4 2E 03 27                                      [?..'------------]

0000000E : dump  (002E)  Packet Data
0000000E :  00 01 08 00 06 04 00 01 00 80 AD B8 2C 82 D4 2E  [........._?,'?.]
0000001E :  03 21 00 00 00 00 00 00 D4 2E 03 27 00 00 00 00  [.!......?..'....]
0000002E :  00 00 00 00 00 00 00 00 00 00 00 00 00 00        [..............--]
-------- End Packet -------

ARP Reply:
-------- Packet -----------, len = 003C
              Ethernet Frame Type: Ethernet II
00000000 : dump  (0006)  Destination Address
00000000 :  00 80 AD B8 2C 82                                [._?,'----------]
00000006 : dump  (0006)  Source Address
00000006 :  00 60 08 76 57 EA                                [.`.vW?----------]
0000000C : word      0806 Protocol
              Protocol: ARP
- - - - - - - - ARP/RARP - - - - - -
0000000E : word      0001 Type of Hardware
            * Ethernet
00000010 : word      0800 Type of Protocol
            * IPv4
00000012 : byte        06 Hardware Address Length
00000013 : byte        04 Protocol Address Length
00000014 : word      0002 Operation
            * ARP Reply
00000016 : dump  (0006)  Sender Hardware Address
00000016 :  00 60 08 76 57 EA                                [.`.vW?----------]
0000001C : dump  (0004)  Sender Protocol Address
0000001C :  D4 2E 03 27                                      [?..'------------]
00000020 : dump  (0006)  Target Hardware Address
00000020 :  00 80 AD B8 2C 82                                [._?,'----------]
00000026 : dump  (0004)  Target Protocol Address
00000026 :  D4 2E 03 21                                      [?..!------------]
0000000E : dump  (002E)  Packet Data
0000000E :  00 01 08 00 06 04 00 02 00 60 08 76 57 EA D4 2E  [.........`.vW??.]
0000001E :  03 27 00 80 AD B8 2C 82 D4 2E 03 21 03 21 03 21  [.'._?,'?..!.!.!]
0000002E :  03 21 03 21 03 21 03 21 03 21 03 21 03 21        [.!.!.!.!.!.!.!--]
-------- End Packet -------

  Gratious ARP

-------- Packet -----------, len = 003C
              Ethernet Frame Type: Ethernet II
00000000 : dump  (0006)  Destination Address
00000000 :  FF FF FF FF FF FF                                [......----------]
00000006 : dump  (0006)  Source Address
00000006 :  00 80 5F 60 EB 3C                                [.__`?<----------]
0000000C : word      0806 Protocol
              Protocol: ARP
- - - - - - - - ARP/RARP - - - - - -
0000000E : word      0001 Type of Hardware
            * Ethernet 10Mb/sec
00000010 : word      0800 Type of Protocol
            * IPv4
00000012 : byte        06 Hardware Address Length
00000013 : byte        04 Protocol Address Length
00000014 : word      0001 Operation
            * ARP Request
00000016 : dump  (0006)  Sender Hardware Address
00000016 :  00 80 5F 60 EB 3C                                [.__`?<----------]
0000001C : dump  (0004)  Sender Protocol Address
0000001C :  C8 C8 C8 D4                                      [????------------]
00000020 : dump  (0006)  Target Hardware Address
00000020 :  00 00 00 00 00 00                                [......----------]
00000026 : dump  (0004)  Target Protocol Address
00000026 :  C8 C8 C8 D4                                      [????------------]

0000000E : dump  (002E)  Packet Data
0000000E :  00 01 08 00 06 04 00 01 00 80 5F 60 EB 3C C8 C8  [.........__`?

  Proxy ARP

  DHCP ARP


84.1.2. РАЗРЕШЕНИЕ ИМЕН

THIS SECTION IS UNDER CONSTRUCTION

  DNS

Смотрите для начала секцию:
    55.9.1.2. СЛУЖБЫ ИМЕН

DNS Request IPv4
- - - - - - - DNS packet - - - - -
00000000 : word      7856 Message ID
00000002 : word      0100 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000000
            * No error
00000004 : word      0001 Number of Requests records
00000006 : word      0000 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (000E)  Domen Symbolic Name
0000000C :  03 77 77 77 05 6C 65 6E 74 61 02 72 75 00        [.www.lenta.ru.--]
0000001A : word      0001 Request/Reply Type
            * A  - IP Address
0000001C : word      0001 Request/Reply Class
            * Internet Object

DNS Reply IPv4
- - - - - - - DNS packet - - - - -
00000000 : word      7856 Message ID
00000002 : word      8180 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [07] * RD (Recurse Desired)
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000008
            * Unknown
00000004 : word      0001 Number of Requests records
00000006 : word      0001 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (000E)  Domen Symbolic Name
0000000C :  03 77 77 77 05 6C 65 6E 74 61 02 72 75 00        [.www.lenta.ru.--]
0000001A : word      0001 Request/Reply Type
            * A  - IP Address
0000001C : word      0001 Request/Reply Class
            * Internet Object
-     -      -   DNS Reply  -     -    -
0000001E : dump  (0002)  Tag
0000001E :  C0 0C                                            [А.--------------]
00000020 : word      0001 Request/Reply Type
            * A  - IP Address
00000022 : word      0001 Request/Reply Class
            * Internet Object
00000024 : dword 00014A87 TTL
00000028 : word      0004 Resourse Info Length
0000002A : dump  (0004)  Resourse Info
0000002A :  C3 E6 5A 1A                                      [ГжZ.------------]

Reverse DNS Request IPv4
- - - - - - - DNS packet - - - - -
00000000 : word      7956 Message ID
00000002 : word      0100 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000000
            * No error
00000004 : word      0001 Number of Requests records
00000006 : word      0000 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (001A)  Domen Symbolic Name
0000000C :  02 33 37 01 33 02 34 36 03 32 31 32 07 69 6E 2D  [.37.3.46.212.in-]
0000001C :  61 64 64 72 04 61 72 70 61 00                    [addr.arpa.------]
00000026 : word      000C Request/Reply Type
            * PTR - Write pointer
00000028 : word      0001 Request/Reply Class
            * Internet Object

Reverse DNS Reply IPv4
- - - - - - - DNS packet - - - - -
00000000 : word      7956 Message ID
00000002 : word      8580 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [07] * RD (Recurse Desired)
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000008
            * Unknown
00000004 : word      0001 Number of Requests records
00000006 : word      0003 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (001A)  Domen Symbolic Name
0000000C :  02 33 37 01 33 02 34 36 03 32 31 32 07 69 6E 2D  [.37.3.46.212.in-]
0000001C :  61 64 64 72 04 61 72 70 61 00                    [addr.arpa.------]
00000026 : word      000C Request/Reply Type
            * PTR - Write pointer
00000028 : word      0001 Request/Reply Class
            * Internet Object
-     -      -   DNS Reply  -     -    -
0000002A : dump  (0002)  Tag
0000002A :  C0 0C                                            [А.--------------]
0000002C : word      000C Request/Reply Type
            * PTR - Write pointer
0000002E : word      0001 Request/Reply Class
            * Internet Object
00000030 : dword 00000384 TTL
00000034 : word      0018 Resourse Info Length
00000036 : dump  (0018)  Resourse Info
00000036 :  08 75 72 72 69 32 6B 70 34 0A 73 74 6F 72 61 63  [.urri2kp4.storac]
00000046 :  74 69 76 65 02 72 75 00                          [tive.ru.--------]
-     -      -   DNS Reply  -     -    -
0000004E : dump  (0002)  Tag
0000004E :  C0 0C                                            [А.--------------]
00000050 : word      000C Request/Reply Type
            * PTR - Write pointer
00000052 : word      0001 Request/Reply Class
            * Internet Object
00000054 : dword 00000384 TTL
00000058 : word      000C Resourse Info Length
0000005A : dump  (000C)  Resourse Info
0000005A :  0A 75 72 72 69 2D 70 34 2D 32 6B 00              [.urri-p4-2k.----]
-     -      -   DNS Reply  -     -    -
00000066 : dump  (0002)  Tag
00000066 :  C0 0C                                            [А.--------------]
00000068 : word      000C Request/Reply Type
            * PTR - Write pointer
0000006A : word      0001 Request/Reply Class
            * Internet Object
0000006C : dword 00000384 TTL
00000070 : word      000A Resourse Info Length
00000072 : dump  (000A)  Resourse Info
00000072 :  08 75 72 72 69 32 6B 70 34 00                    [.urri2kp4.------]

IPv6 DNS Request
- - - - - - - DNS packet - - - - -
00000000 : word      7A56 Message ID
00000002 : word      0100 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000000
            * No error
00000004 : word      0001 Number of Requests records
00000006 : word      0000 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (000F)  Domen Symbolic Name
0000000C :  03 77 77 77 05 36 62 6F 6E 65 03 6E 65 74 00     [.www.6bone.net.-]
0000001B : word      001C Request/Reply Type
            * AAAA - IPv6 Address
0000001D : word      0001 Request/Reply Class
            * Internet Object

IPv6 DNS Reply
- - - - - - - DNS packet - - - - -
00000000 : word      7A56 Message ID
00000002 : word      8180 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [07] * RD (Recurse Desired)
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000008
            * Unknown
00000004 : word      0001 Number of Requests records
00000006 : word      0002 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (000F)  Domen Symbolic Name
0000000C :  03 77 77 77 05 36 62 6F 6E 65 03 6E 65 74 00     [.www.6bone.net.-]
0000001B : word      001C Request/Reply Type
            * AAAA - IPv6 Address
0000001D : word      0001 Request/Reply Class
            * Internet Object
-     -      -   DNS Reply  -     -    -
0000001F : dump  (0002)  Tag
0000001F :  C0 0C                                            [А.--------------]
00000021 : word      0005 Request/Reply Type
            * CNAME - Canonical Name
00000023 : word      0001 Request/Reply Class
            * Internet Object
00000025 : dword 000083F0 TTL
00000029 : word      0002 Resourse Info Length
0000002B : dump  (0002)  Resourse Info
0000002B :  C0 10                                            [А.--------------]
-     -      -   DNS Reply  -     -    -
0000002D : dump  (0002)  Tag
0000002D :  C0 2B                                            [А+--------------]
0000002F : word      001C Request/Reply Type
            * AAAA - IPv6 Address
00000031 : word      0001 Request/Reply Class
            * Internet Object
00000033 : dword 000083F0 TTL
00000037 : word      0010 Resourse Info Length
00000039 : dump  (0010)  Resourse Info
00000039 :  3F FE 0B 00 0C 18 00 01 00 00 00 00 00 00 00 10  [?ю..............]

IPv6 Reverse DNS Request
- - - - - - - DNS packet - - - - -
00000000 : word      7B56 Message ID
00000002 : word      0100 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000000
            * No error
00000004 : word      0001 Number of Requests records
00000006 : word      0000 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (0049)  Domen Symbolic Name
0000000C :  01 30 01 31 01 30 01 30 01 30 01 30 01 30 01 30  [.0.1.0.0.0.0.0.0]
0000001C :  01 30 01 30 01 30 01 30 01 30 01 30 01 30 01 30  [.0.0.0.0.0.0.0.0]
0000002C :  01 31 01 30 01 30 01 30 01 38 01 31 01 43 01 30  [.1.0.0.0.8.1.C.0]
0000003C :  01 30 01 30 01 42 01 30 01 45 01 46 01 46 01 33  [.0.0.B.0.E.F.F.3]
0000004C :  03 69 70 36 03 69 6E 74 00                       [.ip6.int.-------]
00000055 : word      000C Request/Reply Type
            * PTR - Write pointer
00000057 : word      0001 Request/Reply Class
            * Internet Object

IPv6 Reverse DNS Reply
- - - - - - - DNS packet - - - - -
00000000 : word      7B56 Message ID
00000002 : word      8180 Flags
           bits (04,01)   Request Type
                00000000
            * Standart
           [07] * RD (Recurse Desired)
           [08] * RA (Recurse Available)
           bits (0F,0C)   Reply Type
                00000008
            * Unknown
00000004 : word      0001 Number of Requests records
00000006 : word      0001 Number of Replys records
00000008 : word      0000 Number of Base Name Services records
0000000A : word      0000 Number of Additional Info records
-     -      -  DNS Request -    -    -
0000000C : asciiz         Domen Symbolic Name
0000000C : dump  (0049)  Domen Symbolic Name
0000000C :  01 30 01 31 01 30 01 30 01 30 01 30 01 30 01 30  [.0.1.0.0.0.0.0.0]
0000001C :  01 30 01 30 01 30 01 30 01 30 01 30 01 30 01 30  [.0.0.0.0.0.0.0.0]
0000002C :  01 31 01 30 01 30 01 30 01 38 01 31 01 43 01 30  [.1.0.0.0.8.1.C.0]
0000003C :  01 30 01 30 01 42 01 30 01 45 01 46 01 46 01 33  [.0.0.B.0.E.F.F.3]
0000004C :  03 69 70 36 03 69 6E 74 00                       [.ip6.int.-------]
00000055 : word      000C Request/Reply Type
            * PTR - Write pointer
00000057 : word      0001 Request/Reply Class
            * Internet Object
-     -      -   DNS Reply  -     -    -
00000059 : dump  (0002)  Tag
00000059 :  C0 0C                                            [А.--------------]
0000005B : word      000C Request/Reply Type
            * PTR - Write pointer
0000005D : word      0001 Request/Reply Class
            * Internet Object
0000005F : dword 00000030 TTL
00000063 : word      000F Resourse Info Length
00000065 : dump  (000F)  Resourse Info
00000065 :  03 77 77 77 05 36 62 6F 6E 65 03 6E 65 74 00     [.www.6bone.net.-]

TODO: Dynamic DNS

  WINS

THIS SECTION IS UNDER CONSTRUCTION


84.1.3. ПОЛУЧЕНИЕ СЕТЕВЫХ АДРЕССОВ

THIS SECTION IS UNDER CONSTRUCTION

    DHCP
    MADCAP
    APIPA


84.1.4. ROUTING ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

    RIP
    OSPF
    IGRP/EIGRP
    BGP
    DVMRP
    PIM-SM/PIM-DM
    MPLS


84.1.5. ПРОТОКОЛЫ ТУННЕЛИРОВАНИЯ

THIS SECTION IS UNDER CONSTRUCTION

    L2F
    L2TP
    PPTP
    SSTP


84.1.5. ПРОТОКОЛЫ УПРАВЛЕНИЯ СЕТЬЮ

THIS SECTION IS UNDER CONSTRUCTION

    SNMP


84.1.6. QUALITY OF SERVICES (QoS) ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

    RSVP


84.1.7. MOBILITY ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

    Mobile IP


84.1.8.PROXY ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

    SOCKS
    UPnP итд


84.2. ПРИКЛАДНЫЕ ПРОТОКОЛЫ

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


84.2.1. ПРОТОКОЛЫ ЭЛЕКТРОННОЙ ПОЧТЫ

THIS SECTION IS UNDER CONSTRUCTION

  Общий вид взаимодействия по электронной почте

Адресс электронной почты имеет формат:

    имя@домен

1)  Клиент пересылает письмо (письма) на свой SMTP сервер
    Адресс сервера прописан в настройках клиента. Как правило это адресс
    провайдера, если конечно у клиента нет своего почтового сервера.

Кстати клиент может достучаться до сервера и другими путями, например для Microsoft Exchange
общение может происходить через MAPI, который базируется на RPC. Соответсвенно
Microsoft Outlook связанный с Microsoft Exchange это использует

2)  Сервер лезет на DNS сервер у target domain и запрашивает запись
    с типом MX (Mail Exchange). Эта запись возвращает имя mail сервера
    (серверов) для данного домена.

3)  Сервер устанавливает связь с target mail serverом и передает письмо
    по SMTP/ESMTP протоколу.
    (Кстати не обязательно напрямую - бывает что и через сервер провайдера).
    Target server кладет почту в соответсвующий mailbox.
    Если же адрессата нету или ошибки как правило часто отправляют письмо
    на адресс root@домен, этот адресс должен существовать всегда.

В связи с перманентным бедствием именуемым spam, в настоящее время как правило
target серверы проверяют source сервер - что он находится именно в том домене
который он сказал

4)  Target client получает свою почту через POP3 или IMAP4 протокол
    (Может и через MAPI).

  SMTP

SMTP (Simple Mail Transfer Protocol)

SMTP это простой текстовый протокол, ориентированный на передачу US-ASCII,
поэтому тексты в других кодировках или бинарные данные кодируются по Base64 или MIME
(но это уже формат собственно письма).

Сервер: TCP port 25

Команды:

Any Time Commands
----------------------
HELO	domain
EHLO	domain
VRFY	username
VRFY	mailaddr
EXPN	mailaddr
HELP
HELP	cmdname
NOOP
TURN
VERB
ETRN	hostname,domain
QUIT
----------------------

Mail transaction Commands
----------------------
MAIL FROM:<...>		Send Email
RCPT TO:<..>		Specify recipitient of message
SEND FROM:<...>        	Send Message to User Terminal
SOML FROM:<...>         Send Message to User Terminal if terminal active,
            else in message box
SAML FROM:<...>         Send Message to Terminal and to message box
NOOP			Return 250 OK, used for check connection
RSET			Reset transaction, all  recorded senders, recepients
            and mailbox data must be flushed, and server must
            send 250 OK
TURN			Turn Sender and Receiver Client/Server functions,
            used for exchange between mail hosts
            Then it will done server will send 250,
            elsewhere 502
DATA			Before start sending data
----------------------

Other commands:
 --------------------
ATRN	domain		Authenticated turn
AUTH	login		Authenticate
ETRN	[option] node	Extended Authenticated turn
SIZE	size	       	Specify size of message
MAIL  FROM:<..> SIZE=size
 --------------------

Code	Description
 ----------------------------------
211	System Status Message
214	Help Message
220	Service Ready
221	Service Closing
250	Command complete successfully
251	Recipient not local but will forward
354	Start message input, end with CRLF.CRLF
421	Service not available
450	Command failed because the mailbox is unavailable (Mailbox locked)
451	Command aborted due to server error
452	Command not completed due to insufficient system storage
500	Command unrecognized (syntax error)
501	Syntax error in command arguments
502	Command not implemented
503	Bad sequence of commands
504	Command parameter not implemented
550	Mailbox not found
551	User not local, try
552	Command aborted because client has exceeded storage location
553	Command aborted because the mailbox name is invalid
554	Transaction failed
 ----------------------------------

Вoт как выглядет сеанс связи:

------------------------------------------------
C:	HELO	myname.mydomain
S:	250 Hello,please to meet you
C:	MAIL FROM:	Sender Address
S:	250 OK
    Possibly usage of 'MAIL FROM:<>'
C:	RCPT TO:          Target Address
S:	250 OK
C:	DATA
S:	354 Start mail input; end with .
C:	Here is mail headers and body
C:	still continued
C:	Ended with line, which contain only . (dot) at start
C: 	.
S:	250 OK
C:	QUIT
S:	221 Closing Transmission channel
------------------------------------------------

--------------------------------
S:	220 mit.edu Simple Mail Transfer Service
C:	HELO usc.edu
S:	250 mit.edu
C:	MAIL FROM:
S:	250 OK
C:	RCPT TO:
S:	250 OK
C:	RCPT TO:
S:	550 No such user here
C:	RCPT TO:
S:	250 OK
C:	DATA
S:	354 Start mail input; end with .
C:
C:
C:	.
S:	250 OK
C:	QUIT
S:	221 mit.edu Service closing Transmission channel
--------------------------------------------

------------------------------------------------
C:	HELO	myname.mydomain
S:	250 Hello,please to meet you
C:	MAIL FROM:	Sender Address
S:	250 OK
    Possibly usage of 'MAIL FROM:<>'
C:	RCPT TO:          Target Address
S:	550 Failure
------------------------------------------------

------------------------------------------------
C:	HELO	myname.mydomain
S:	250 Hello,please to meet you
C:	MAIL FROM:	Sender Address
S:	250 OK
    Possibly usage of 'MAIL FROM:<>'
C:	RCPT TO:          Target Address
S:	550 Failure
------------------------------------------------

------------------------------------------------
C:	HELO	myname.mydomain
S:	250 Hello,please to meet you
C:	MAIL FROM:	Sender Address
S:	250 OK
    Possibly usage of 'MAIL FROM:<>'
C:	RCPT TO:          Target Address
S:	251 User not local; will forward to <...>
------------------------------------------------

------------------------------------------------
C:	HELO	myname.mydomain
S:	250 Hello,please to meet you
C:	MAIL FROM:	Sender Address
S:	250 OK
    Possibly usage of 'MAIL FROM:<>'
C:	RCPT TO:          Target Address
S:	551 User not local; please try <...>
------------------------------------------------

Также есть возможность проверить существует ли ящик:

------------------------------------------------
C:	VRFY	username
S:	250	usernames
------------------------------------------------

------------------------------------------------
C:	EXPN	Example-People
S:	250-Jon Postel <...>
S:	250-Fred Fonebone <...>
S:	250-
S:	250
------------------------------------------------

  POP3

POP3 (Post Office Protocol v3)

Сервер:
TCP port  110		POP3
TCP port  995		POP3 over TLS/SSL

Commands for Authorization state:
    USER
    PASS
    APOP
    AUTH
    QUIT
Commands for Transaction state:
    STAT
    LIST
    RETR			      get message
    DELE
    NOOP
    RSET                                          unmark all deleted msgs
    QUIT
    TOP	     get first N lines of msg
    UIDL

POP3 server status lines:
    +OK message
    -ERR message

EXAMPLE OF POP3 SESSION
No new mail:
-------------------------------------
S: +OK mpop 4.19 ready.
C: USER phg
S: +OK phg selected
C: PASS password
S: +OK Congratulations!
C: STAT
S: +OK 0 0
C: QUIT
S: +OK goodbye.
-------------------------------------

  IMAP4

TCP port	143	IMAP
TCP port	993	IMAP over TLS/SSL

IMAP4 Commands:
-----------------------------------
    NOOP
    CAPABILITY
    LOGOUT
    AUTHENTICATE
    LOGIN		username  password
    CREATE		mailbox
    DELETE		mailbox
    SELECT		mailbox
    EXAMINE		mailbox
    RENAME		existingmailbox newmailbox
    SUBSCRIBE	mailbox
    UNSUBSCRIBE	mailbox
    APPEND		mailbox,flags,date/time,message literal
    LIST		name_with_wildcards
    LSUB		name_with_wildcards
    STATUS		mailbox
    FETCH		message_set, message_data_item_names
    STORE		message_set, message_data_item_names, message_data
    CHECK
    EXPUNGE
    SEARCH		charset_definition, search_criterias
    COPY		message_set mailbox name
    CLOSE
    UID?		command name argument
-----------------------------------


84.2.2. ПРОТОКОЛЫ НОВОСТЕЙ

THIS SECTION IS UNDER CONSTRUCTION

    NNTP


84.2.3. ПРОТОКОЛЫ ТЕРМИНАЛЬНОГО ДОСТУПА

THIS SECTION IS UNDER CONSTRUCTION

    Telnet
    SSH


84.2.4. ПРОТОКОЛЫ ГРАФИЧЕСКИХ ТЕРМИНАЛОВ

THIS SECTION IS UNDER CONSTRUCTION

    X-Windows System Protocol
    RDP


84.2.5. ПРОТОКОЛЫ ПЕРЕДАЧИ ФАЙЛОВ

THIS SECTION IS UNDER CONSTRUCTION

    TFTP
    FTP


84.2.6. ПРОТОКОЛЫ СЕТЕВЫХ ФАЙЛОВЫХ СИСТЕМ (NAS)

THIS SECTION IS UNDER CONSTRUCTION

    NFS
    NCP
    CIFS + SMB2
    AFP
    other


84.2.7. STORAGE AREA NETWORK ПРОТОКОЛЫ (SAN)

THIS SECTION IS UNDER CONSTRUCTION

    iSCSI
    iFC
    AoE


84.2.8. ПРОТОКОЛЫ ДЛЯ ВРЕМЕНИ

THIS SECTION IS UNDER CONSTRUCTION

    SNTP
    NTP


84.2.9. WEB

THIS SECTION IS UNDER CONSTRUCTION

TODO: Покрыть и техническую и социальную части


84.2.9.1.1. ПРОТОЛЫ ПЕРЕДАЧИ ДАННЫХ WEB

THIS SECTION IS UNDER CONSTRUCTION

    HTTP
    WebDAV


84.2.9.1.2. ЯЗЫК РАЗМЕТКИ HYPERTEXT

THIS SECTION IS UNDER CONSTRUCTION

    HTML
    CSS


84.2.9.1.3. DYNAMIC HTML

THIS SECTION IS UNDER CONSTRUCTION

    Scripting
    DOM


84.2.9.1.4. ПОДДЕРЖКА НА СТОРОНЕ СЕРВЕРА

THIS SECTION IS UNDER CONSTRUCTION

    CGI
    ISAPI/NSAPI
    Servlets
    ASP
    PHP


84.2.9.1.5. AJAX

THIS SECTION IS UNDER CONSTRUCTION

    AJAX (Asyncronous JavaScript and XML)


85.2.9.2. КОНТЕКСТНАЯ ЧАСТЬ WEB

THIS SECTION IS UNDER CONSTRUCTION

Домашние странички
Поисковые системы
    Spyders
Интернет магазины
Форумы
Blogs
Wiki
YouTube
Социальные сети
Файловые хранилища - например Rapidshare


84.2.10. ПРОТОКОЛЫ ДЛЯ ЧАТА

THIS SECTION IS UNDER CONSTRUCTION

    IRC
    ICQ
    Skype


84.2.11. DIRECTORY SERVICES ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

    NDS
    LDAP
    NIS


84.2.12. ПРОТОКОЛЫ ПЕЧАТИ

THIS SECTION IS UNDER CONSTRUCTION

    Связанные с Network filesystem протоколами
    LPD
    IPP


84.2.13. ФАЙЛООБМЕННЫЕ ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

    eD2K
    Napster
    GNUtella


84.2.14. ПРОТОКОЛЫ ТОРГОВЛИ

THIS SECTION IS UNDER CONSTRUCTION

    SET
    IOTP


84.2.15. ПРОТОКОЛЫ ПОТОКОВОГО MULTIMEDIA

THIS SECTION IS UNDER CONSTRUCTION

    RTP
    RTCP
    RTSP
    SIP
    SDP


84.2.16. ЗАГРУЗОЧНЫЕ ПРОТОКОЛЫ

THIS SECTION IS UNDER CONSTRUCTION

    RPL
    PXE


90. ИСКУССТВО УПРАВЛЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

Действующие лица в Software проекте
Административная структура

    CTO
        Development
            Chief architecter
                Architectors
            Team Leader
                Programmers
            Technology
            Research
        Release Team
            Chief Release Team
                Release Engeneer
        QA
            Chief QA
                QA Lead
                    QA Engeneer
        Support
            Chief Support
                Support Lead
                    Support Engeneer
        Management
            PM   - продуктовая ответсвенность
            DPM  - разработка
            RPM  - выпуск продукта
        Marketing
            Marketing
            Web
                Web design
                Web marketing
            Design
                UI desing
                Usability group
        HR

    внешние
        подрядчики
        заказчики
        пользователи

Project management
    основные методики
        Extreme
        Ajile

Задачи управления
    Административное
    Проектное

    Набор кадров
    Мотивация персонала
    Обучение персонала
    Аттестация персонала

    Проектные документы
        Vision
        SOW (Statement of Work)

        Test Cases
        Test Plan
        Test Report
        Bug Report

    Bug Scrab

    Сбор требований
    Уточнение требований
    Декомпозиция
    Планирование задач
    Risk management
    Постановка задач
    Отслеживание выполнения задач


99. ДРУГИЕ ТЕХНОЛОГИИ

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

Вычислительные системы (эволюция):

    Механические
    Электромеханические (релейная логика)
    Электроламповые
    Транзисторные
    Микросхемы
    СБИС (Сверхбольшие интегральные схемы)


99.1. ПНЕВМОНИКА

  Источник давления

Диод

  Резистор

  NOT

        GND       Pout
    \   \    |   |
     \    +--+ ^ |
          \        | |
        \      | +---  Pin
          \    |   <---
               \   | +---
                 + | |
                 | | |
                   Vcc

Используется эффект прилипания струи газа к стенке.

  AND

          GND     Pout       GND
      \  \   | ^ |    /
       \   \ | | |  /   /
            \   \| | |/   /
             \     |    /
         ----+     |   +----
    Pin2  -------->+<------- Pin1
     -----+         +---
           \       /
        +-----+

Струи газа сталкиваясь уходят в выход

  OR

        Pout      GND
    \   \    |   |
     \    +--+ ^ |
          \        | |
       \       | +---
        \      | <----  Pin1
             \     | +---
          \    | <----  Pin2
               \   | +---
                 + | |
                 | | |
                   Vcc

Опять эффект прилипания.

  Транзистороподобные структуры

  Пневмоника

Плюсы: 	стойкость к агрессивным средам
              к радиации
          к магнитным и электрическим полям
    способность работать при высоких (> 500 'C)
        и низких (вблизи 10K) температурах.

Размер элемента:  5x5x2.5 mm  (V = 60 mm^3)
Частота:	  2-3 kGHz

    Zilog Z80: 8500 транзисторов
    На пневмонике: 8500*60 = 21*10^4 mm^3 = 210 sm^3
               1 sm^3 = 1000 mm^3
    т.e. Zilog Z80 занимал бы стакан.
    (правда работал бы в 1000 раз медленнее).


99.2. РЕЛЕЙНАЯ ЛОГИКА

  NOT

  AND

  OR

  Триггер


99.3. ЭЛЕКТРОННЫЕ ЛАМПЫ

  Лампы

Действие электронных ламп основано на явлении термоэлектронной эмиссии.
Катод нагревают до температуры порядка 1000'C. При такой температуре
электроны вылетают из катода и если они будут подхвачены электрическим
полем то они будут двигатся.

  Диод

Простейшая электронная лампа - это диод.
Диод имеет только катод и анод.
Если на анод подать + напряжение относительно катода то электроны
с катода летят на анод и возникает ток.
При напряжении на аноде 0V идет некоторый начальный ток.
При напряжении на аноде -0.5V ток практически не идет.
Таким образом диод пропускает ток только в одном направлении
(как и его полупроводниковый аналог).

  Триод

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

Схема подключения триода:

Пример работы схемы:

Проблема триода - это проходная емкость (анод-сетка). При большой частоте
это приводит к провалам в выходной характеристике триода.

  Тетрод

Тетрод отличается от триода наличием дополнительной сетки как правило
заземленной через конденсатор (это уменьшает проходную емкость).

Пример усилителя на тетроде:

Проблема тетрода - динатронный эффект.
При разнице потенциалов 100V электроны набирают скорость ~ 6000 км/сек
Ударяясь о сетки они выбивают вторичные электроны, которые тоже летят
к аноду вызывая нежелательный ток.

  Пентод

Пентод отличается от тетрода наличием дополнительной редкой (с большими
ячейками) сетки - антидинатронной сетки. На сетке поддерживается напряжение
которое тормозит электроны.
Быстрые электроны от катода пролетают без проблем
Медленные от вторичной электронной эммисии тормозятся и заворачиваются обратно.

  Схемы на лампах

  NOT

Инвертер на Лампах:
(принципы все те же что и в полупроводниковых устройствах).

  OR

  NAND

  Триггер

Логические злементы на лампах Вы можете сконструировать самостоятельно
опираясь на материал данного раздела и на схемы элементов на полупроводниках.


99.3.1. ПАМЯТЬ НА ФЕРИТОВЫХ СЕРДЕЧНИКАХ

THIS SECTION IS UNDER CONSTRUCTION


99.3.2. ВНЕШНЯЯ ПАМЯТЬ НА МАГНИТНЫХ БАРАБАНАХ

THIS SECTION IS UNDER CONSTRUCTION


99.4. DL

DL - Diode Logic

AND:

OR:


99.5. RTL

RTL - Resistor Transtor Logic

NOR3:


99.6. DTL

DTL - Diode Transistor Logic

NOR:

NAND:


99.8. РЕАЛИЗАЦИЯ ТРОИЧНОЙ ЛОГИКИ

THIS SECTION IS UNDER CONSTRUCTION

  CMOS

Троичный OR.

  BJT

  NOT

  Rotate Down

  Shift Up

  Shift Down

  OR (MAX)

  AND (MIN)


99.9. ОПТИЧЕСКИЕ ВЫЧИСЛЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

Интерферометр Фабри-Перо:


99.10. КВАНТОВЫЕ ВЫЧИСЛЕНИЯ

THIS SECTION IS UNDER CONSTRUCTION

THIS SECTION IS UNDER CONSTRUCTION

    Максимизация плотности вычислений (на единицу объема)
    Минимизация тепловыделения

Если вычисления стирает один бит информации то при этом выделяется
энергия по меньшей мере
    E = ln(2) * k * T
    k - константа Больцмана
    T - температура

  Классика:
    вычисления идут только в точках стабильного сигнала
  Квантовые:
    вычисления идут не только в точках стабильного сигнала

    состояния имеют ненулевую амплитуду во многих местах
    в одно время (квантовый паралелизм)

C-bits
    {0,1}
    Irreversible
    Reversible

Reversible Logic
    логически:  информация остается
        (например AND не reversible - кушает информацию).
    физически:  сколько сигналов ввели - столько и вывели
            (в смысле состояний 0/1, т.е. нигде ничего не  вводили/
            выводили

    Irreversible логические элементы - рассевивают мощность в окружение.
    потому что у них связи с source и sink

  Топология квантовых вычислений

Квантовые вычисления
    не могут быть копированы (no fun-out)
    не могут быть стерты (no fun-in)
    количество выходных линий = количеству входных линий

т.е. вычисления идут как обмен сигналов
     данные идут векторами это q-bits (кубиты) - например пара {A, A#}

Позволяются только линейные структуры с линейными логическими элементами
Циклы не позволяются

Плохая:

  Reversible элементы

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

  NOT

  CNOT

CNOT  (Controlled NOT) (Reversible XOR)

COPY  CNOT(X,0) = (X,X)
на самом деле копирование не полное. Копируются только строго определенные
состояния кубита 0 или 1.

  CCNOT

CCNOT (Controlled-Controlled NOT) (Toffoli gate)

AND   CCNOT(X1, X2, 0) = (X1, X2, X1 AND X2)

  SWAP

В квантовой логике мы платим за пересечение проводников

  CSWAP

(CSWAP - Controlled SWAP)
Fredkin gate

  Полусумматор

  Полный сумматор

  Квантовые основы

Кубит:
Qubit (Quantun-bit)

Сфера Блоша (Bloch)

2-кубиты

  Квантовые элементы

  H (Квадратный корень из NOT)

Оптическая имплементация H и пример NOT:

  X (NOT)

  Y

  Z

  Phase Shift

  Rotate

  Сложные квантовые элементы

Упрощение сложных функций:
U = V^2

U = V^4

Более сложные примеры:


99.11. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ НА ЭФФЕКТЕ ДЖОЗЕФСОНА

Электроника сверхпроводимости

THIS SECTION IS UNDER CONSTRUCTION

SQUID (Superconducting Quantum Interference Device)

RSFQ logic (Rapid Single Flux Quantum)

    туннельный переход через 10 Aнгстрем изолятор (SIS)
    два пленочных СП через 100 Ангстрем металла (SNS)
    мостик - два СП соединенные тонким СП

Куперовские пары - 2 электрона со спинами
не подчиняются статистике Ферми-Дирака
а подчиняются Бозе-Энштейна
Конденсируются на одном нижнем уровне
большой размер  - 1мкм

Сила тока через Переход Джозефсона

    I = Ic sin Ф

    Ф = Ф1 - Ф2	(разница фаз волновых функций электронов)

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

    носители информации - кванты магнитного потока Ф0

    Ф = n * Ф0

Тактирование Ф0

DC-Squid

RT-Squid

j-ADC:


100. TESTBENCH

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

Пример компонент (NOT4 инвертор):

    library ieee;
    use ieee.std_logic_1164.all;

    entity Not4 is
        port(
                A : in std_logic;
                D : out std_logic);
    end Not4;

    architecture Example of Not4 is
    begin
        D <= not A after 2 ns;
    end Example;

TestBench for NOT4 инвертор:

    library ieee;
    use ieee.std_logic_1164.all;

    ENTITY tb is
                -- no need for any ports or generics
    End Not4_tb ;

    architecture arch of tb IS
        component Not4 is
            port(
                A : in std_logic;
                    D : out std_logic );
        end component;

        constant period	: time := 50 ns ;
        signal   clk    : std_logic := '0';  -- Initial state zero
        signal   AA, DD : std_logic := '0';
    begin
            U1: Not4
                port map(
                    D      => DD,
                    A      => AA) ;

            ClkProcess: PROCESS(clk)	     -- Generate clock
        begin
            if (clk = '1') then
                AA <= not AA;
            end if;
                clk <= NOT clk after period / 2 ;
        end process;
    end arch;


100.1. ГЕНЕРАЦИЯ CLK СИГНАЛА

Пример аппаратной генерации CLK сигнала:

Для генерации CLK сигнала используются кварцевые генераторы.
Основа пьезоэлектрический эффект:
делается специальный срез кристалла.

    если нажать на кристалл кварца то на концах возникнет заряд
    Если приложить напряжение то кристалл деформируется.

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

Кварцевый генератор

    Один из основных сигналов для тестирования это CLK (сигнал
синхронизации.
Это template кода для генерации CLK сигнала на VHDL:

    constant  period: time := 50 ns;  -- Full CLK cycle
    signal    CLK : std_logic := '0';

    ....

    ClkProcess : process(CLK)
        CLK <= not CLK after period/2;
    end process;

Это template кода для генерации CLK сигнала на Verilog:

    module	pulse;
        reg	clock;
        initial	clock = 1'b0;
        always #10 clock = ~clock;
        initial #5000 $finish
    endmodule


100.2. ГЕНЕРАЦИЯ СИГНАЛА RESET

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

Идея: сразу при включении питания конденсатор не заряжен, пока он
будет заряжатся, инвертор Шмитта будет иметь на входе 0, на выходе 1,
а  когда зарядится то на входе будет 1, на выходе 0.

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

Это template кода для генерации RESET сигнала на VHDL:

    signal RST: std_logic := '0';

    ....

    ResetProcess : process
        wait until(CLK = '0');	  -- Synchronous Reset
        RST <= '0','1' after 10 ns,
               '0' afert 20 ns;
    end process;


100.3. TESTBENCH ДЛЯ РЕАЛЬНОЙ ЖИЗНИ

Что включает в себя TestBench для реальной жизни?

1. Макетные платы (много и разных).

2. Лабораторный блок питания (не все же время сидеть на +5V).

3. Двухканальный Мультиметр-Осциллограф обязательно с интерфейсом
к компьютеру.

4. Провода.
5. Радиоэлектронные компоненты.


200. ЗАДАЧИ И УПРАЖНЕНИЯ

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


200.1. ЗАДАЧИ К ВВЕДЕНИЮ (1.X)

  1.1

1.1.A)
   Расчитать свой рост в аттопарсеках.

1.1.B)
   Чему равны 5 наносекунд в пикогодах?

1.1.C)
   Чему равен 1 терабайт в байтах, на сколько % это больше чем тебибайт?


200.2. ЗАДАЧИ К БУЛЕВОЙ АЛГЕБРЕ (2.X)

  2.1

2.1.A)
    Определить по таблице истинности, и назвать что это за функция:
    2.1.A.1)
        0 0 | 0
        0 1 | 1
        1 0 | 0
        1 1 | 1
    2.1.A.2)
        0 0 | 0
        0 1 | 1
        1 0 | 0
        1 1 | 0
    2.1.A.3)
        0 0 0 | 0
        0 0 1 | 1
        0 1 0 | 1
        0 1 1 | 1
        1 0 0 | 0
        1 0 1 | 1
        1 1 0 | 1
        1 1 1 | 0

2.1.B) 	Написать таблицу истинности для функции:
    2.1.B.1) A xor B#
    2.1.B.2) XOR(A,B,C,D)
    2.1.B.3) A xor B xor C#
    2.1.B.4) C + A*B*C#
    2.1.B.5) A nand B# nor C#
    2.1.B.6) A imp B or A# xor C

  2.2

2.2.A) 	Нарисовать диаграмму Венна для функции:
    2.2.A.1)  A xor B#
    2.2.A.2)  A and (B or C)
    2.2.A.3)  IMP(A,B) xor NAND(B,C)

  2.4

2.4.A)	Упростить выражение
          2.4.A.1)   F = AB#D + AB#D#
    2.4.A.2)   F = (A# + B)*(A + B)
    2.4.A.3)   F = ACD + A#BCD
    2.4.A.4)   F = AC# + ABC#
    2.4.A.5)   F = A#BC#CD# + A#B#C#D#
    2.4.A.6)   F = A#D + ABD
    2.4.A.7)   F = AB#C# + AB#C + ABC
    2.4.A.8)   F = (A# + B)*(A + B + D)*D#
    2.4.A.9)   F = C#((ABD)# + D) + AB#C + D#
    2.4.A.10)  F = AB#C + A#B#C + A#B#C# + A#BC# + ABC#

2.4.B)
   Представить логические функции NOT, AND, OR в виде выражения
   через Штрих Шеффера.
   (Пример через стрелку Пирса (\ - стрелка пирса):
    A AND B = A# \ B# = (A \ A) \ (B \ B)

  2.5

2.5.A)	Привести в нормальную конъюктивную форму:

THIS SECTION IS UNDER CONSTRUCTION

2.5.B)	Привести в нормальную дезъюктивную форму:

THIS SECTION IS UNDER CONSTRUCTION

  2.5.1

2.5.1.A) Расчитать Булевский дифференциал для функции:

THIS SECTION IS UNDER CONSTRUCTION

  2.6

2.6.A)	Нарисовать карту Карно для всех логических функций 2х переменных

2.6.B)	Нарисовать карту Карно для функции:
    2.6.B.1) XOR(A,B,C,D) or B#
    2.6.B.2) A nand B# nor C#
    2.6.B.3) A imp B or A# xor C

2.6.C) 	Соптимизировать функцию пользуясь картой Карно
    2.6.C.1)
        1101
        0000
        0001
        1101
    2.6.C.2)
        0010
        1001
        1001
        0010
    2.6.C.3)
        1100
        0010
        1101
        0101
    2.6.C.4)
        1011
        1011
        1100
        1000
    2.6.C.5)
        1111
        1001
        0001
        0001
    2.6.C.6)
        0000
        1101
        1101
        0000
    2.6.C.7)
        0111
        0100
        1001
        0001
    2.6.C.8)
        1111
        0X00
        10XX
        X10X
    2.6.C.9)
        0111
        01X0
        101X
        000X
    2.6.C.10)
        01X1
        0X10
        XX01
        1001

2.6.D)	Соптимизировать функцию заданную таблицей истинности пользуясь картой Карно:
    2.6.D.1)	01101010
    2.6.D.2)	01111111
    2.6.D.3)	X10X1XX1
    2.6.D.4)	101XX110
    2.6.D.5)	XX1X0X10
    2.6.D.6)	01001000
    2.6.D.7)	11010101

  2.7

2.7.A) Определить Линейность, Монотонность, Самодвойственность,
       Сохранение 0 и 1 для функций:

THIS SECTION IS UNDER CONSTRUCTION

  2.8

2.8.A)
   Представить в полиномальной форме функции:
    XOR, NAND, NOR, AND, OR

  2.10

2.10.A)
   Представить 3-ичные логические функции
    AND, OR, XOR, исключающий MAX
    через функцию Уэбба.

  2.15

2.15.A) Нарисовать все перестановки для числа переменных N = 6


200.3. ЗАДАЧИ К СИСТЕМАМ СЧИСЛЕНИЯ (3.X)

  3.3

   Перевести в следующие системы счисления (2,3,4,7,8,16,36)
   числа:
    123456789 [10]
    11#01#1#101# [3#]
    EBAD [16]
    BAFF [16]
    HZ   [36]

  3.4.1

   Написать таблицы сложения и умножения для сбалансированной
   cемиричной системы счисления:
        ----------
    цифры:	3#   (-3)
        2#   (-2)
        1#   (-1)
        0
        1
        2
        3
        ----------

  3.X

   Вычислить в заданной системе счисления:
    F * F 			[16]
    FF * FF 		[16]
    ABCE + 3FC5     	[16]
    356  + 737      	[8]
    1#10111# - 101#101#	[3#]


200.4. ЗАДАЧИ К ПРОЧИМ СЕКЦИЯМ

THIS SECTION IS UNDER CONSTRUCTION

  5.X

   Нарисовать схемы делающие из одного из данных триггеров другой
   с помощью логики:
        RS -> T
        D  -> RS
        D  -> JK

  7.X

   Нарисовать схему на элементах логики для дешифратора на
   стандартный семисегментный индикатор (0..F)

   Нарисовать CMOS топологию дешифратора 2 в 4

  8.X

   Нарисовать CMOS топологию мультиплексора  4x1

  10.X

   Нарисовать схему на элементах логики для мажоритарного элемента
   на 5-входов.

   Нарисовать карту Карно для мажоритарного элемента на 5-входов.

  11.X

   Нарисовать карту Карно для одноразрядного полусумматора и полного
   сумматора.

   Посчитать флаги (ZF,CF,OF,SF,PF) и результат для следующих вычислений
   (все числа в 16-ричной системе счистления)
    BYTE	37 + 85
    BYTE	7E + 61
    BYTE	E1 + 1F
    WORD	1234 + 9876
    WORD	FE21 + FFAC

    BYTE x BYTE -> WORD  E0 * E5  Signed
    BYTE x BYTE -> WORD  E0 * E5  Unsigned
    BYTE x BYTE -> WORD  80 * 7F  Signed
    BYTE x BYTE -> WORD  80 * 7F  Unsigned

  57.X

   Предложить схему аналогового делителя

  99.X

   Разработать пневмонические элементы для NAND и NOR.

   Нарисовать OR на релейной логике

   Разработать элементы NAND и OR на электронных лампах

   разработать исключающий MAX на BJT


300. СПИСОК ЛИТЕРАТУРЫ

THIS SECTION IS UNDER CONSTRUCTION

Литература к COMPUTER BASIS.

  Электроника

П.Хоровиц, У.Хилл
"Искусство схемотехники"
в трех томах
Москва Мир 1993
ISBN 5-03-002337-2
ISBN 5-03-002338-0
ISBN 5-03-002954-0

В.И. Карлащук
"Электронная лаборатория на IBM PC
Программа Electronic Workbench и ее применение"
Москва СОЛОН-ПРЕСС 2003
ISBN 5-98003-020-4

К.C.Петров
"Радиоматериалы, Радиокомпоненты и Электроника"
М Питер 2004
ISBN 5-94723-378-9

  Системы счисления и арифметика

Генри Уоррен мл
"Алгоритмические трюки для программистов"
М Вильямс 2003
ISBN 5-8459-0471-4

E.Андреева, И.Фалина
"Системы счисления и компьютерная арифметика"
М Бином 2004
ISBN 5-94774-117-2

А.А Папернов
"Логические основы ЦВТ"
М Советское радио 1972

  Цифровая электроника

М.И.Богданович, И.Н. Грель, В.А. Прохоренко
"Интегральные цифровые микросхемы"
Минск Беларусь 1991
ISBN 5-338-00501-8

Е.Угрюмов
"Цифровая схемотехника"
СП bhv 2000
ISBN 5-8206-0100-9

Ю.В Новиков
"Основы цифровой схематехники
Базовые элементы и схемы
методы проектирования"
М Мир 2001
ISBN 5-03-003449-8

Г.И. Пухальский, Т.Я. Новосельцева
"Цифровые устройства"
СП Политехника 1996
ISBN 5-7325-0359-5

Рональд Дж. Точчи, Нил С. Уидмер
"Цифровые системы: теория и практика"
8е
М Виллиямс 2004
ISBN 5-8459-0586-9

Дж Уэйкерли
"Проектирование цифровых устройств"
М Постмаркет 2002
ISBN 5-901095-12-X

  HDL

Е.А. Суворова, Ю.Е. Шейнин
"Проектирование цифровых систем на VHDL"
СП БЧВ-Петебург 2003
ISBN 5-94157-189-5

В.Ю. Зотов
"Проектирование цифровых устройств
на основе ПЛИС фирмы Xilinx в САПР WebPACK ISE"
М Горячая линия-Телеком 2003
ISBN 5-93517-136-8

П.Н. Бибило
"Основы языка VHDL"
М Солон-Р 2000
ISBN 5-93455-056-X

П.Н. Бибило
"Синтез логических схем с использованием языка VHDL"
М Солон-Р 2002
ISBN 5-93455-152-3

Сергиенко А.М.
"VHDL для проектирования вычислительных устройств"
Киев ЧП "Корнейчук", ООО "ТИС-Д"
ISBN 966-7599-32-9

Перельрозен Е.З.
"Проектируем на VHDL"
М Солон-Пресс 2004
ISBN 5-98003-113-8

А.К. Поляков
"Языки VHDL и Verilog в проектировании цифровой аппаратуры"
М Солон-Пресс 2003
ISBN 5-98003-016-6

  Архитектура

Б.А. Головкин
"Вычислительные системы с большим числом процессоров"
М Радио и связь 1995
ISBN 5-256-01076-X

Уильям Столлингс
"Структурная организация и архитектура компьютерных систем"
5 издание
М Вильямс 2002
ISBN 5-8459-0262-2

Э. Таненбаум
"Архитектура компьютера"
4 издание
СП Питер 2002
ISBN 5-318-00298-6

К.Хамакер, З.Вранешич, С.Заки
"Организация ЭВМ"
5 издание
СП Питер 2003
ISBN 5-8046-0162-8

Г. Хелд
"Технологии передачи данных"
7 издание
СП Питер 2003
ISBN 5-94723-472-6

Бернард Скляр
"Цифровая связь:
Теоретические основы и практическое применение"
2е издание
М Вильямс 2003
ISBN 5-8459-0497-8

Вильям Столлингс
"Компьютерные системы передачи данных"
6 издание
М Вильямс 2002
ISBN 5-8459-0311-4

Вильям Столлингс
"Безпроводные линии связи и сети"
М Вильямс 2003
ISBN 5-8459-0409-9

Михаил Гук
"Аппаратные средства IBM PC
Энциклопедия"
2 издание
СП Питер 2001
ISBN 5-318-00047-9

Б.Я. Цилькер, С.А. Орлов
Организация ЭВМ и систем
СП ПИТЕР 2004
ISBN 5-94723-759-8

Б.В.Шевкопляс
Микропроцессорные структуры
Инженерные решения
Справочник 2е издание
М Радио и Связь 1990
ISBN 5-256-00973-7

Б.В.Шевкопляс
Микропроцессорные структуры
Инженерные решения
Справочник
Дополнение первое
М Радио и связь 1993
ISBN 5-256-00973-7
 2е издание

  Прочее

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

THIS SECTION IS UNDER CONSTRUCTION

  Обзорные книги по семействам микропроцессоров

Б.Соучек
Микропроцессоры и Микро-ЭВМ
М Советское радио 1979
[4004/4040, 8008/8080, MC6800 итд]

Дж.Уокерли
"Архитектура и программирование микро-ЭВМ"
в 2-х книгах
М Мир 1984
[PDP-11, MC68000, Z8000, TMS9900, MC6809, 8086]

А литература на English я просто крякну набивать. :(

Mi Lu
"Arithmetic and Logic in Computer Systems"
Wiley 2004
ISBN 0-471-46945-9
 ISBN 0471469459


401. ДОПОЛНИТЕЛЬНАЯ ОБЩАЯ ИНФОРМАЦИЯ

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

    Hackers School в лице Васильева Ильи.

Печатное издание данного текста запрещено без письменного согласия автора.
Нарушители будут нести ответственность в соответствии с нормами Российского
(или местного) законодательства.


402. SOFTWARE

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

Эмуляция (SPICE) и рисование электрических схем:
    Electronic Workbench Pro 5
    (сейчас есть более новые версии:
        MultiSim 2001
        MultiSim 7)

    Circuit Maker 2001

HDL языки (VHDL/Verilog):
    Symphony EDA Sonata		(VHDL)
    Xilinx Foundation Express	(VHDL/Verilog)
    OrCAD 9.1			(VHDL)
    ModelSim 5.x			(VHDL/Verilog)
    MultiSim 2001			(в первую очередь Verilog)

Схемотехника:
    OrCAD 9.1

Layout:
    Tanner L-Edit

Моделирование нелинейных систем:
    National Semiconductor	 LabVIEW 7
    SimuLink (MatLAB extension)
    Elanix SystemView

Математические пакеты:
    MatLAB
    Mathematica
    MAPLE
    MathCAD

Статистические пакеты:
    StatSoft Statistica 6
    SPSS

При создании данного документа использовaлось Software:
    Microsoft HTML Help compiler
    Microsoft Visio
    Adobe Photoshop 6
    etc


403. PHG

PHG (Potemkin's Hackers Group) существует начиная с 1992 года.

Структура курсов

    Computer Basics

    Операционные системы (API)
    Операционные системы (Архитектура и Дизайн)
    Операционные системы (Драйверы)

    Networking (Протоколы)
    Networking (API)
    Networking (Архитектура)
    Networking (Драйверы)

    Middleware

    Архитектура Storage и Файловые системы

    Языки программирования (обзор)
    Языки программирование (кодогенерация)
    Стандартные библиотеки

    Базовые алгоритмы
    Алгоритмы: Криптография
    Алгоритмы: Колорметрия, машинная графика и обработка изображений
    Алгоритмы: Компрессия
    Алгоритмы: Звук

    Микропроцессоры (x86)
    Микропроцессоры (основные)
    Микропроцессоры (специфические)
    Микропроцессоры (археология)

    Базовое железо

    AI

    World Wide Web технологии

также существуют и другие темы.

Наши продукты
    операционная система VS/OS
    язык программирования PGL
    мультиплатформенная среда разработки PDE


404. ОБ АВТОРЕ

  Education

Физико-математическая школа #2, г.Москва

Московский Государственный Университет им М.В.Ломоносова
факультет ВКНМ

  Work

Группа компаний ДВМ

Дом научно технического творчества молодежи (ДНТТМ)

Лицей информационных технологий

PHG

Storactive Inc.

Acronis Inc.

В настоящее время

Compiled by APX2CHM v1.25v. © PHG 2002..2009. Build Date 27-Apr-2010


Computer Basis

INTRO

0. INTRO.
0.0. ВНИМАНИЕ ПРОЧИТАЙТЕ ЭТУ СЕКЦИЮ
0.1. ЦЕЛИ
1. УРОВНИ ПОНИМАНИЯ РАБОТЫ КОМПЬЮТЕРА
1.1. ЧИСЛА И ПРИСТАВКИ СИ
1.2. ФИЗИЧЕСКИЕ ВЕЛИЧИНЫ И ИХ СВЯЗЬ ДРУГ С ДРУГОМ

БУЛЕВА АЛГЕБРА

2. БУЛЕВА АЛГЕБРА: ОПРЕДЕЛЕНИЯ
2.1. ЛОГИЧЕСКИЕ ФУНКЦИИ
2.2. АЛГЕБРА ЛОГИКИ НА ПАЛЬЦАХ
2.3. АКСИОМЫ АЛГЕБРЫ ЛОГИКИ
2.4. ЗАКОНЫ АЛГЕБРЫ ЛОГИКИ
2.5. НОРМАЛЬНАЯ ФОРМА ЛОГИЧЕСКОЙ ФУНКЦИИ
2.5.1. БУЛЕВСКИЙ ДИФФЕРЕНЦИАЛ
2.6. КАРТЫ КАРНО
2.6.1. ОПТИМИЗАЦИЯ МЕТОДОМ КУИНА-МАККЛАСКИ
2.6.1.1. ЛОГИКА РИДА-МИЛЛАРА
2.6.2. ВЫВОД ЗА ПРЕДЕЛЫ ДНФ
2.7. БАЗИС
2.8. ПОЛИНОМАЛЬНАЯ ФОРМА
2.8.1. РАЗЛОЖЕНИЕ ЛОГИЧЕСКИХ ФУНКЦИЙ
2.9. СИММЕТРИЧЕСКИЕ ФУНКЦИИ
2.10. ЛОГИКА БОЛЕЕ ВЫСОКИХ ПОРЯДКОВ
2.11.1. ТРОИЧНАЯ ЛОГИКА
2.11.2. ЧЕТВЕРИЧНАЯ ЛОГИКА
2.12. КОЛИЧЕСТВО ЛОГИК
2.13. ЖЕНСКАЯ ЛОГИКА
2.14. ДИАГРАММЫ ВЕННА
2.15. НЕМНОГО КОМБИНАТОРИКИ
2.16. ФОРМАЛЬНАЯ ЛОГИКА
2.17. ПЕРЕКЛЮЧАТЕЛЬНАЯ ЛОГИКА

СИСТЕМЫ СЧИСТЛЕНИЯ

3. СИСТЕМЫ СЧИСЛЕНИЯ
3.1. НЕПОЗИЦИОННЫЕ СИСТЕМЫ СЧИСЛЕНИЯ
3.2. ПОЗИЦИОННЫЕ СИСТЕМЫ СЧИСЛЕНИЯ
3.3. СХЕМА ГОРНЕРА И ПРЕОБРАЗОВАНИЯ В ДРУГУЮ СИСТЕМУ СЧИСТЛЕНИЯ
3.3.1. ДРОБНЫЕ ЧИСЛА
3.4.1. ДВОИЧНАЯ СИСТЕМА СЧИСЛЕНИЯ
3.4.2. ПРОСТАЯ ТРОИЧНАЯ СИСТЕМА
3.4.3. ЧЕТВЕРИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ
3.4.4. ВОСМЕРИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ
3.4.5. ДЕСЯТИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ
3.3.6. ШЕСТНАДЦИТЕРИЧНАЯ СИСТЕМА СЧИСТЛЕНИЯ
3.4.7. СИСТЕМА СЧИСЛЕНИЯ С ОСНОВАНИЕМ 36
3.5. CБАЛАНСИРОВАННЫЕ СИСТЕМЫ СЧИСЛЕНИЯ
3.5.1. СБАЛАНСИРОВАННАЯ ТРОИЧНАЯ СИСТЕМА
3.5.2. СБАЛАНСИРОВАННАЯ ПЯТИРИЧНАЯ СИСТЕМА СЧИСЛЕНИЯ
3.5.3. СБАЛАНСИРОВАННАЯ ДЕВЯТНАДЦАТИРИЧНАЯ СИСТЕМА СЧИСЛЕНИЯ
3.5.4. ИЗБЫТОЧНАЯ СБАЛАНСИРОВАННАЯ СИСТЕМА С ОСНОВАНИЕМ 4
3.5.5. НЕИЗБЫТОЧНАЯ ЧАСТИЧНО-СБАЛАНСИРОВАННАЯ СИСТЕМА С ОСНОВАНИЕМ 4
3.5.6. СБАЛАНСИРОВАННАЯ ДЕВЯТИРИЧНАЯ СИСТЕМА СЧИСЛЕНИЯ
3.6. CИСТЕМА СЧИСЛЕНИЯ С ОСНОВАНИЕМ -2
3.7. СИСТЕМЫ СЧИСЛЕНИЯ С КОМПЛЕКСНЫМИ ОСНОВАНИЯМИ
3.8. НЕТРАДИЦИОННЫЕ СЧ (ЭКЗОТИКА)
3.9. BCD
3.10.1. ПРОСТЫЕ ИРРАЦИОНАЛЬНЫЕ СЧ
3.10.2 СИСТЕМА БЕРГМАНА
3.11. ОПТИМАЛЬНАЯ СИСТЕМА СЧИСЛЕНИЯ
3.12. ПРЕДСТАВЛЕНИЕ ОТРИЦАТЕЛЬНЫХ ЧИСЕЛ В CЧ С НАТУРАЛЬНЫМ ОСНОВАНИЕМ.
3.13. КОМПЛЕКСНЫЕ ЧИСЛА
3.14. ПРОСТРАНСТВЕННЫЕ КОМПЛЕКСНЫЕ ЧИСЛА
3.15. ЗОЛОТОЕ СЕЧЕНИЕ
3.16. НЕМНОГО ОБЩЕЙ АЛГЕБРЫ
3.16.1. КВАДРАТНЫЕ МАТРИЦЫ
3.16.2. ВЕКТОРНАЯ АЛГЕБРА
3.16.3. КВАТЕРНИОНЫ
3.16.4. НЕМНОГО ТЕОРИИ ЧИСЕЛ
3.16.4.1. КОЛЬЦА ВЫЧЕТОВ
3.17.1. ПОЛЯ ГАЛУА GF[p]
3.17.2. ПОЛИНОМАЛЬНАЯ АРИФМЕТИКА
3.17.3. ПОЛЯ ГАЛУА GF[p,k]
3.18. СМЕШАННЫЕ ОСТАТОЧНЫЕ КОЛЬЦА (RNS)
3.19. ДРОБНЫЕ СИСТЕМЫ СЧИСЛЕНИЯ
3.20. ПРИЗНАКИ ДЕЛИМОСТИ
3.21. СИСТЕМЫ СЧИСТЛЕНИЯ С ДВОЙНЫМ ОСНОВАНИЕМ

ЦИФРОВАЯ ЭЛЕКТРОНИКА И ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ

4. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ
4.1. ЭЛЕКТРИЧЕСКИЕ СИГНАЛЫ
4.1.1. УРОВНИ СИГНАЛОВ
4.1.2. КАК ЧИТАТЬ ВРЕМЕННЫЕ ДИАГРАММЫ
4.1.3. УРОВНИ СИГНАЛОВ В HDLs
4.2. ПАССИВНЫЕ ЭЛЕКТРИЧЕСКИЕ КОМПОНЕНТЫ
4.3.1. ФИЗИЧЕСКИЕ ОСНОВЫ
4.3.2. ДИОД
4.3.3. ТРАНЗИСТОР БИПОЛЯРНЫЙ (BJT)
4.3.4. ТРАНЗИСТОР ПОЛЕВОЙ (JFET)
4.3.5. MOSFET ТРАНЗИСТОР
4.3.6. ПОЛЯРНОСТЬ ТРАНЗИСТОРОВ
4.4. КРЕМНЕВЫЕ ТЕХНОЛОГИИ
4.4.1. ЭЛЕКТРИЧЕСКИЕ ОСНОВЫ (NMOS)
4.4.2. ЭЛЕКТРИЧЕСКИЕ ОСНОВЫ (CMOS)
4.4.2.1. ТОПОЛОГИЯ CMOS
4.4.2.2. СЛОЖНАЯ ЛОГИКА НА CMOS
4.4.2.3. ЗАПИРАЮЩИЙ ЭЛЕМЕНТ
4.4.2.4. BiCMOS ТЕХНОЛОГИЯ
4.4.2.5. ДИНАМИЧЕСКАЯ CMOS ЛОГИКА
4.4.2.6. БОРЬБА ЗА ПОНИЖЕННОЕ ЭНЕРГОПОТРЕБЛЕНИЕ В IDLE РЕЖИМЕ
4.4.2.7. PTL (PASS-TRANSISTOR LOGIC)
4.4.2.8. РЕАЛИЗАЦИЯ ЛОГИЧЕСКИХ ФУНКЦИЙ
4.4.3. ЭВОЛЮЦИЯ
4.4.3.1. РАЗГОН CMOS
4.4.3.2. СОВРЕМЕННЫЕ ТЕХНОЛОГИИ
4.4.4.1. ЗАЩИТА ВХОДОВ И ВЫХОДОВ
4.4.4.2. ОТКРЫТЫЕ СТОКИ И ШИНЫ
4.4.4.3. СОВРЕМЕННЫЕ ЭЛЕКТРИЧЕСКИЕ ШИНЫ
4.4.5. ЭМИТЕРНО-СВЯЗАННАЯ ЛОГИКА
4.4.5.1. ТРИГГЕР ШМИТТА
4.4.5.2. ЭЛЕМЕНТ ЗАДЕРЖКИ
4.4.6. I2L ЛОГИКА (ИНЖЕКТОРНАЯ ЛОГИКА)
4.4.7. TTL ЛОГИКА
4.4.8. DCFL
4.5. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ НА HDL ЯЗЫКАХ
4.5.1. СТОИМОСТЬ ЛОГИЧЕСКИХ ЭЛЕМЕНТОВ
4.5.2. ЗАДЕРЖКИ
4.5.3. РАЗВЕТВЛЕНИЯ
4.5.4. СИНХРОНИЗАЦИЯ
4.5.5. ПОМЕХИ И ПОТЕРИ
4.5.6. СОПРЯЖЕНИЕ МЕЖДУ СОБОЙ РАЗЛИЧНЫХ ТЕХНОЛОГИЙ
4.6. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ НА ДИСКРЕТНЫХ КОМПОНЕНТАХ
4.7. МОДЕЛИРОВАНИЕ НА ЭЛЕКТРОННОМ УРОВНЕ И SPICE
4.8. ТЕХНОЛОГИЯ ИЗГОТОВЛЕНИЯ МИКРОСХЕМ
4.9. ПЕЧАТНЫЕ ПЛАТЫ

ТРИГГЕРЫ

5. ТРИГГЕРЫ
5.1. АСИНХРОННАЯ RS-ЗАЩЕЛКА
5.2. RS-ТРИГГЕР
5.3. JK-ТРИГГЕР
5.4. D-ТРИГГЕР
5.5. T-ТРИГГЕР
5.6. ГЕНЕРАЦИЯ ИМПУЛЬСОВ ПО ФРОНТАМ
5.7. ДВУХСТУПЕНЧАТЫЕ ТРИГГЕРЫ И ЗАЩЕЛКИ
5.8. DETFF

ФУНКЦИОНАЛЬНО-ЛОГИЧЕСКИЙ УРОВЕНЬ

6. КОМБИНАЦИОННЫЕ СХЕМЫ
6.0. ОБЩИЕ МЕТОДЫ ПОСТРОЕНИЯ КОМБИНАЦИОННЫХ СХЕМ
6.0.1. ГЛИЧИ
7. ДЕШИФРАТОР
7.1. СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР
7.2. ПРИОРИТЕТНЫЙ ШИФРАТОР
7.3. ПРЕОБРАЗОВАТЕЛЬ КОДОВ
8. МУЛЬТИПЛЕКСОР
9. КОМПАРАТОР
10. МАЖОРИТАРНЫЙ ЭЛЕМЕНТ
10.1. ПОРОГОВЫЙ ЭЛЕМЕНТ
11.1. ПОЛУСУММАТОР
11.2. ПОЛНЫЙ СУММАТОР
11.3. КАСКАД СУММАТОРОВ
11.4. СУММАТОР С УСКОРЕННЫМ ПЕРЕНОСОМ
11.5. СУММАТОРЫ С БЫСТРЫМ РАСПРОСТРАНЕНИЕМ ПЕРЕНОСА
11.6. ВЫЧИТАНИЕ
11.7. ОТКУДА БЕРУТСЯ ФЛАГИ?
11.8. СУММАТОР НЕИЗВЕСТНОГО РАЗМЕРА НА HDL
11.9. ПОСЛЕДОВАТЕЛЬНЫЙ СУММАТОР
11.10. BCD СУММАТОР
11.11. СУММАТОР С НАСЫЩЕНИЕМ
11.12. СУММАТОРЫ/ВЫЧИТАТЕЛИ ДЛЯ ДРУГИХ (НЕ ДОПОЛНЕНИЕ ДО ДВУХ) СХЕМ
11.13. ИСПОЛЬЗОВАНИЕ СУММАТОРО-ПОДОБНЫХ СТРУКТУР ДЛЯ ВЫПОЛНЕНИЯ ПРОЧИХ ОПЕРАЦИЙ
11.14. ИСПОЛЬЗОВАНИЕ СУММАТОРОВ ДЛЯ RSN
12. СДВИГОВЫЙ РЕГИСТР
13. СЧЕТЧИКИ
13.1. ОБРАТНАЯ СВЯЗЬ В СЧЕТЧИКАХ
13.2. ПОСЛЕДОВАТЕЛЬНО-ПАРАЛЕЛЬНЫЙ РЕГИСТР И СЧЕТЧИКИ
14. УМНОЖИТЕЛЬ
14.1. СЕМЕЙСТВО МЕТОДОВ БУТА
14.2. МАТРИЧНЫЕ УМНОЖИТЕЛИ
14.3. ДРЕВОВИДНЫЕ УМНОЖИТЕЛИ
14.4. УМНОЖЕНИЕ БЕЗ СЛОЖЕНИЯ (NMM)
14.5. УМНОЖИТЕЛИ: ИТОГИ
15. ДЕЛЕНИЕ В CPU
15.1. АППАРАТНОЕ ВЫЧИСЛЕНИЕ КВАДРАТНОГО КОРНЯ
16. КОНТРОЛЬ ОШИБОК И КОРРЕКТИРУЮЩИЕ КОДЫ
16.1. КОНТРОЛЬ ЧЕТНОСТИ
16.1.1. КОД ПОВТОРЕНИЕ
16.2. КОМПОЗИЦИОННЫЕ КОДЫ
16.3. КОД ХЭММИНГА
16.4. ГЕОМЕТРИЧЕСКИЙ СМЫСЛ ДИСТАНЦИИ
16.4.1. ГРАНИЦА ХЭММИНГА
16.4.2. КОД ГОЛЕЯ
16.4.3. КОДЫ РИДА-МИЛЛАРА
16.5. CRC (ЦИКЛИЧЕСКАЯ КОНТРОЛЬНАЯ СУММА)
16.6. КОДЫ РИДА-СОЛОМОНА
16.7. КОД БЕРГЕРА
16.8. СВЕРТОЧНЫЕ КОДЫ
16.9. ТУРБО КОДЫ
16.9.1. EVENODD КОДЫ
16.9.2. WEAVER КОДЫ
17. КОД ГРЕЯ
18. РЕГИСТРЫ
19. ШИННЫЕ БУФЕРА И ШИННЫЕ ФОРМИРОВАТЕЛИ
20.1. ЦАП
20.2. АЦП
20.3. ГЕНЕРАТОРЫ СИГНАЛОВ
21. ДВОЙНАЯ СИНХРОНИЗАЦИЯ
22. ДЕТЕРМИНИРОВАННЫЕ КОНЕЧНЫЕ АВТОМАТЫ
24. CPLD И FPGA

ПАМЯТЬ

25. ПАМЯТЬ
25.0 SRAM (СТАТИЧЕСКАЯ ПАМЯТЬ)
25.1. ROM
25.2. PROM
25.3. EPROM И EEPROM
25.3.1. FLASH
25.3.2. FeRAM
25.4. DRAM
25.4.1. СИГНАЛЫ DRAM
25.4.2. ЭВОЛЮЦИЯ DRAM
25.5. ОБЩИЕ ПРИНЦИПЫ РАСШИРЕНИЯ СИСТЕМ ПАМЯТИ

МИКРОПРОЦЕССОР

30. МИКРОПРОЦЕССОР (CPU)
30.1. ALU
30.1.1. РЕАЛИЗАЦИЯ ALU НА VHDL.
30.2. ФАЙЛ РЕГИСТРОВ
30.2.1. ПРИМЕРЫ ФАЙЛА РЕГИСТРОВ
30.3. CONTROL UNIT
30.3.1. ВЫПОЛНЕНИЕ ТИПИЧНЫХ ОПЕРАЦИЙ
30.3.1.1. РЕГИСТР ФЛАГОВ И УСЛОВИЯ
30.3.1.2. DECODER
30.3.2. ADDRESS GENERATION UNIT
30.3.2.1. СТЕК
30.3.3. ПРЕРЫВАНИЯ
30.3.3.1. ИСКЛЮЧЕНИЯ
30.3.4. АРХИТЕКТУРА ИНСТРУКЦИЙ
30.3.5. СОЗДАЕМ СВОЙ НАБОР ИНСТРУКЦИЙ
30.3.6. КОНВЕЕРИЗАЦИЯ В ПРОЦЕССОРЕ
30.4. BUS INTERFACE UNIT
30.4.1. АРБИТРАЖ ШИНЫ
30.4.2. ПОВЫШЕНИЕ БЫСТРОДЕЙСТВИЯ ШИНЫ
30.4.3. НЕВЫРОВНЕННОЕ ОБРАЩЕНИЕ К ПАМЯТИ
30.4.4. СЕМАФОРНЫЕ ОПЕРАЦИИ И БЛОКИРОВАНИЕ ШИНЫ
30.4.5. ЗАПРОСЫ НА ПРЕРЫВАНИЯ
30.5. FLOATING POINT UNIT
30.5.1. FP UNIT CONTROL AND STATUS REGISTERS
30.6. MULTIMEDIA UNIT
30.6.1. ОСОБЕННОСТИ ПРОГРАММИРОВАНИЯ MULTIMEDIA UNIT

ОБЗОР СИСТЕМ КОМАНД СОВРЕМЕННЫХ МИКРОПРОЦЕССОРОВ

35. ОБЗОР СОВРЕМЕННЫХ МИКРОПРОЦЕССОРОВ
35.1.1. DEC ALPHA
35.1.2. MOTOROLA 68K
35.1.3. POWER PC
35.1.4. MIPS
35.1.5. SPARC
35.1.6. HP-PA
35.1.7. IA-32 (X86)
35.1.7.2. X86-64 (AMD64)
35.1.8. IA-64
35.1.9. ARM
35.2. НАБОРЫ КОМАНД
35.2.1 ЦЕЛОЧИСЛЕННЫЕ КОМАНДЫ
35.2.1.1. АРИФМЕТИЧЕСКИЕ КОМАНДЫ
35.2.1.2. ЛОГИЧЕСКИЕ КОММАНДЫ
35.2.1.3. СДВИГИ И ВРАЩЕНИЯ
35.2.1.4. РАБОТА С ПАМЯТЬЮ
35.2.1.4.2. СЕМАФОРНЫЕ ОПЕРАЦИИ
35.2.1.5. ПЕРЕСЫЛКА И ПРЕОБРАЗОВАНИЕ ДАННЫХ
35.2.1.6. СРАВНЕНИЯ И УСЛОВНЫЕ ПЕРЕХОДЫ
35.2.1.7. ВЫЗОВ И ВОЗВРАТ ИЗ ПОДПРОГРАММ, БЕЗУСЛОВНЫЕ ПЕРЕХОДЫ
35.2.1.8. УСЛОВНЫЕ ПЕРЕСЫЛКИ И УСТАНОВКИ
35.2.1.9. ОПЕРАЦИИ С БИТАМИ И БИТОВЫМИ СТРОКАМИ
35.2.1.10 ОПЕРАЦИИ СО СТЕКОМ
32.2.2.11. НЕКОТОРЫЕ СИСТЕМНЫЕ КОМАНДЫ
35.2.2. FP КОММАНДЫ
35.2.3. ЦЕЛОЧИСЛЕННЫЕ ВЕКТОРНЫЕ КОММАНДЫ
35.2.3.1. INTEGER VECTOR CODE ISA SUMMARY
35.2.4. FP ВЕКТОРНЫЕ КОММАНДЫ
35.2.4.1. FLOATING POINT VECTOR SUMMARY
35.3. DETAILED INSTRUCTION SET SUMMARY
35.3.1 INTEGER ARITHMETICAL INSTRUCTIONS
35.3.2 INTEGER LOGICAL INSTRUCTIONS
35.3.3 INTEGER SHIFT/ROTATES INSTRUCTIONS
35.3.4 INTEGER LOAD/STORE INSTRUCTIONS
35.3.5 INTEGER CONVERTIONS INSTRUCTIONS
35.3.6. COMPARES AND CONDITIONAL JUMPS INSTRUCTIONS
35.3.7. UNCONDITIONAL JUMPS AND CALLS INSTRUCTIONS
35.3.8 INTEGER CONDITIONAL MOVES AND SETS INSTRUCTIONS
35.3.9 INTEGER BITS AND BITSTRINGS INSTRUCTIONS

АРИФМЕТИКА И ЧИСЛА С ПЛАВАЮЩЕЙ И ФИКСИРОВАННОЙ ТОЧКОЙ

40. ПРЕДСТАВЛЕНИЕ ВЕЩЕСТВЕННЫХ ЧИСЕЛ
40.1. ЧИСЛА С ПЛАВАЮЩЕЙ ТОЧКОЙ
40.1.1. ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ТОЧКОЙ
40.1.2. ВЫЧИСЛЕНИЕ СЛОЖНЫХ ФУНКЦИЙ
40.1.3. РЕАЛЬНЫЕ ОПЕРАЦИИ
40.2. ЧИСЛОВАЯ ЛОГАРИФМИЧЕСКАЯ СИСТЕМА
40.2.1. ОПЕРАЦИИ В NLS
40.2.2. ПРЕМУЩЕСТВА NLS
40.3. LI И SLI СИСТЕМЫ
40.10. ЛОГАРИФМЫ
40.11. ФОРМУЛА ТЕЙЛОРА
40.12. НЕКОТОРЫЕ СВЕДЕНИЯ ИЗ ТРИГОНОМЕТРИИ
40.13. BCD12 ЧИСЛА С ПЛАВАЮЩЕЙ ТОЧКОЙ
41. АРИФМЕТИКА
41.1. АРИФМЕТИКА С ФИКСИРОВАННОЙ ТОЧКОЙ
41.2. АРИФМЕТИКА С НАСЫШЕНИЕМ
41.3. АРИФМЕТИКА ДВОЙНОЙ И МНОГОКРАТНОЙ ТОЧНОСТИ
41.4. СООТНОШЕНИЯ В ДОПОЛНИТЕЛЬНОМ КОДЕ
41.5. РЕАЛИЗАЦИЯ СПЕЦИАЛЬНЫХ ФУНКЦИЙ
41.6 УМНОЖЕНИЕ НА КОНСТАНТУ
41.7 ДЕЛЕНИЕ НА КОНСТАНТУ
41.8. FP ХАКИ

МИКРОАРХИТЕКТУРА

50. АРХИТЕКТУРА МИКРОПРОЦЕССОРОВ
50.1. ФОН НЕЙМАНОВСКАЯ И ГАРВАРДСКАЯ АРХИТЕКТУРА
50.2. ПОСЛЕДОВАТЕЛЬНАЯ, ПАРАЛЛЕЛЬНАЯ И КОНВЕЕРНАЯ АРХИТЕКТУРА
50.2.1. ПРИМЕРЫ КОНВЕЕРОВ РЕАЛЬНЫХ ПРОЦЕССОРОВ
50.3. СКАЛЯРНЫЕ И ВЕКТОРНЫЕ АРХИТЕКТУРЫ
50.3.1. МАТРИЧНЫЕ ПРОЦЕССОРЫ
50.3.2. ВЕКТОРНЫЕ ПРОЦЕССОРЫ (СУПЕРКОМПЬЮТЕРЫ)
50.3.3. SOFTWARE PIPELINING
50.3.3. ОРГАНИЗАЦИЯ ОБРАБОТКИ ДАННЫХ
50.4. RISC И CISC АРХИТЕКТУРЫ
50.5. OUT-OF-ORDER EXECUTION
50.6. HYPERTHREADING, MULTIPROCESSING и MULTICORE
50.7. CACHE
50.7.1. CACHE SNOOP
50.7.2. МИКРООПЕРАЦИИ И КЭШИРОВАНИЕ КОДА
50.8. ПРЕДВЫБОРКА
50.9. ПРЕДСКАЗАНИЕ ПЕРЕХОДОВ
50.9.1. ОТЛОЖЕННЫЕ ПЕРЕХОДЫ
50.10. ПЕРЕИМЕНОВАНИЕ РЕГИСТРОВ И РЕГИСТРОВЫЕ ОКНА
50.11. АДРЕСНОЕ ПРОСТРАНСТВО И ВИРТУАЛЬНАЯ ПАМЯТЬ
50.12.1. СПЕКУЛЯТИВНАЯ ЗАГРУЗКА И ДРУГИЕ ХИТРОСТИ С ПАМЯТЬЮ
50.13. ЗАЩИТА
50.14. ТЕНДЕНЦИИ В ENVIRONMENT
50.15. УРОВНИ ПАРАЛЛЕЛИЗМА
50.16. ВИРТУАЛИЗАЦИЯ
50.17. АППАРАТНАЯ ПОДДЕРЖКА ОТЛАДКИ
50.18. МИКРОКОНТРОЛЛЕРЫ
51. АРХИТЕКТУРА ВВОДА-ВЫВОДА
51.1. ГИПЕРКУБЫ

ОСНОВЫ ПЕРЕДАЧИ И ХРАНЕНИЯ ДАННЫХ

55. ОСНОВЫ ПЕРЕДАЧИ И ХРАНЕНИЯ ДАННЫХ
55.0. АНАЛОГ И ЦИФРА
55.1. ПОСЛЕДОВАТЕЛЬНАЯ И ПАРАЛЕЛЬНАЯ ПЕРЕДАЧА/ХРАНЕНИЕ ДАННЫХ
55.1.1.ПАРАЛЕЛЬНО-ПОСЛЕДОВАТЕЛЬНЫЕ ПРЕОБРАЗОВАТЕЛИ
55.2. ПОЛОСА ПРОПУСКАНИЯ
55.2.1. ЧТО ТАКОЕ ДУПЛЕКС
55.3. РАЗВЯЗКИ
55.3.0. ДИФФЕРЕНЦИАЛЬНАЯ ПЕРЕДАЧА СИГНАЛОВ
55.3.1. КОММУТАЦИЯ
55.3.2. ФИЗИЧЕСКАЯ ТОПОЛОГИЯ
55.3.3. УПЛОТНЕНИЕ СИГНАЛОВ
55.3.4. СРЕДЫ ОБЩЕГО ДОСТУПА
55.3.5. ОСНОВНЫЕ НЕСУЩИЕ СРЕДЫ
55.3.5.1. ВОЛНОВОЕ СОПРОТИВЛЕНИЕ КАБЕЛЯ
55.3.5.2. POTS (PLAIN OLD TELEPHONE SERVICES) И DSL
55.4.1. ПРОБЛЕМЫ СИНХРОНИЗАЦИИ
55.4.2. ИСКАЖЕНИЕ СИГНАЛОВ: ФИЗИЧЕСКИЕ ОСНОВЫ
55.4.3. МОДЕЛЬ КАНАЛА
55.5. КОДИРОВАНИЕ
55.5.1. ЛОГИЧЕСКОЕ КОДИРОВАНИЕ
55.5.2. ФИЗИЧЕСКОЕ КОДИРОВАНИЕ
55.5.3. КАДРЫ
55.6. МОДУЛЯЦИЯ
55.6.1. РЕАЛИЗАЦИЯ МОДУЛЯТОРОВ И ДЕТЕКТОРОВ
55.7. ПЕРЕДАЧА АНАЛОГОВЫХ ДАННЫХ ПО ЦИФРОВЫМ КАНАЛАМ
55.8. ПЕРЕДАЧА АНАЛОГОВЫХ ДАННЫХ ПО АНАЛОГОВЫМ КАНАЛАМ
55.9. СЕТИ
55.9.1. ПОВТОРЕНИЕ ПЕРЕДАЧИ
55.9.2. ТИПЫ СЕТЕЙ
55.9.3. СЕТЕВЫЕ СЕРВИСЫ
55.9.3.1. РАЗРЕШЕНИЕ АДРЕССОВ В ЛОКАЛЬНОМ СЕГМЕНТЕ СЕТИ
55.9.1.2. СЛУЖБЫ ИМЕН
55.9.3.2. ТИПЫ АДРЕССОВ
55.9.3.4. МАРШРУТИЗАЦИЯ
55.9.4. КАК РАБОТАЕТ МАРШРУТИЗАТОР ROUTER
55.9.5. КАК РАБОТАЕТ КОММУТАТОР (SWITCH)
55.10. ХРАНЕНИЕ ДАННЫХ
55.10.0. RAID
55.10.1. МАГНИТНЫЕ НОСИТЕЛИ
55.10.1.1. ЛЕНТЫ
55.10.2. ОПТИЧЕСКИЕ НОСИТЕЛИ
55.10.3. МАГНИТО-ОПТИЧЕСКИЕ НОСИТЕЛИ
55.10.4. ТРЕХМЕРНАЯ ПАМЯТЬ
55.10.5. ДРУГИЕ НОСИТЕЛИ
55.11. ФАЙЛОВЫЕ СИСТЕМЫ
55.11.1. КЛАСТЕРНЫЕ ФАЙЛОВЫЕ СИСТЕМЫ
55.11.1. ДИСКОВЫЕ РАЗДЕЛЫ И УПРАВЛЕНИЕ ТОМАМИ
55.50. ГРАФЫ
55.51. КРАТЧАЙШИЙ ПУТЬ В ГРАФЕ
55.52. МИНИМАЛЬНОЕ ОСТОВНОЕ ДЕРЕВО
55.53. МАКСИМАЛЬНЫЙ ПОТОК
55.54. ПАРАЛЕЛЬНЫЕ АЛГОРИТМЫ НАД ГРАФАМИ

ВНЕШНИЕ УСТРОЙСТВА

56. ВНЕШНИЕ УСТРОЙСТВА
56.0. УРОВЕНЬ РЕГИСТРОВ HARDWARE
56.0.1. LED
56.0.2. КНОПКИ И ПЕРЕКЛЮЧАТЕЛИ
56.0.3. СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР
56.1. КЛАВИАТУРА
56.2. ВИДЕО ВЫВОД
56.2.1. GPU
56.3. УСТРОЙСТВА ВВОДА
56.4. ПРИНТЕР
56.5. СКАНЕР
56.6. ЗВУКОВАЯ ПОДСИСТЕМА
56.7. ПАРАЛЛЕЛЬНЫЙ ПОРТ
56.8. ПОСЛЕДОВАТЕЛЬНЫЙ ПОРТ
56.9. GAME ПОРТ
56.10. СЕТЕВАЯ КАРТА
56.50. ДАТЧИКИ
56.51. УПРАВЛЕНИЕ ТИПОВЫМИ УСТРОЙСТВАМИ
57. АНАЛОГОВЫЕ ВЫЧИСЛЕНИЯ
57.0. АНАЛОГОВЫЙ ТАЙМЕР
57.1. СХЕМЫ ФАЗОВОЙ АВТОПОДСТРОЙКИ

СХЕМОТЕХНИКА PC

60. СХЕМОТЕХНИКА PC
60.1. ШИНА ISA
60.2. ШИНА PCI
60.3.1. DMA
60.3.2. PIC
60.3.3. PIT
60.3.4. RTC
60.3.5. FDC
60.3.6. USB
60.3.7. КОНТРОЛЛЕР ПАМЯТИ
61. СИЛОВАЯ ЭЛЕКТРОННИКА

БАЗОВЫЕ СТРУКТУРЫ ДАННЫХ

70.1. ОСНОВНЫЕ УПРАВЛЯЮЩИЕ КОНСТРУКЦИИ
70.1.1. ПАРАЛЕЛЬНЫЕ КОНСТРУКЦИИ
70.2. ОСНОВНЫЕ СТРУКТУРЫ ДАННЫХ
70.2.1. ЦЕЛЫЕ ТИПЫ И ENDIAN
70.2.1.1. ТИПЫ С ПЛАВАЮЩЕЙ ТОЧКОЙ
70.2.1.2. ВЕКТОРНЫЕ ТИПЫ ДАННЫХ
70.2.1.3. ПОЛЬЗОВАТЕЛЬСКИЕ ТИПЫ ДЛЯ ЧИСЛОВЫХ ДАННЫХ
70.2.2. СТРУКТУРЫ И ВЫРАВНИВАНИЕ
70.2.2.1. БИТЫ И БИТОВЫЕ ПОЛЯ
70.2.3. ПРЕДСТАВЛЕНИЕ СИМВОЛОВ
70.2.4. УКАЗАТЕЛИ И МОДЕЛИ ПАМЯТИ
70.2.5. MACCИВЫ
70.2.5.1. БИТОВЫЕ МАССИВЫ (BITMAP)
70.2.6. СТРОКИ
70.2.6.1. КОНЦЕТУАЛЬНЫЙ RTL ДЛЯ СТРОК
70.2.6.1.0. ПРОКЛАДКИ ДЛЯ КОНВЕРТАЦИИ СТРОК
70.2.6.1.1. АЛГОРИТМЫ НА СТРОКАХ
70.2.6.2. КОНВЕРТАЦИЯ ЧИСЕЛ В СТРОКИ И ОБРАТНО
70.2.6.3. ФОРМАТНЫЙ ВЫВОД В СТРОКИ
70.2.6.3.1. DUMP
70.2.6.4. СТРОКИ И РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ
70.2.6.5. СПИСКИ СТРОК
70.2.6.6. ПОТОКОБЕЗОПАСНЫЕ СТРОКИ
70.2.6.7. ТИПОВЫЕ СТРОКОВЫЕ ИНТЕРФЕЙСЫ
70.2.7. КОЛЛЕКЦИИ
70.2.8. ОБОБЩЕННЫЕ АЛГОРИТМЫ
70.2.9. ПОТОКОБЕЗОПАСНЫЕ КОЛЛЕКЦИИ
70.3. ОБЩИЕ ВОПРОСЫ
70.3.1. ГЕНЕРАЦИЯ СЛУЧАЙНЫХ И ПСЕВДОСЛУЧАЙНЫХ ЧИСЕЛ
70.3.2. АЛГОРИТМЫ СОРТИРОВКИ
70.3.3. АЛГОРИТМЫ ПОИСКА
70.3.4. КОМБИНАТОРНЫЕ АЛГОРИТМЫ
70.4. НЕКОТОРЫЕ ИНФРАСТРУКТУРНЫЕ ВОПРОСЫ
70.4.1. ОБРАБОТКА ОШИБОК
70.4.3. ПОТОКИ ДАННЫХ
70.4.4. СЕРИАЛИЗАЦИЯ ОБЪЕКТОВ
70.5. К ВОПРОСАМ О ПАРАЛЛЕЛИЗАЦИИ АЛГОРИТМОВ
70.6. ОСНОВНЫЕ ПАРАДИГМЫ

ЯЗЫКИ ПРОГРАММИРОВАНИЯ

71. ЯЗЫКИ ПРОГРАММИРОВАНИЯ
71.1. ИМПЕРАТИВНЫЕ ЯЗЫКИ ПРОГРАММИРОВАНИЯ
71.1.1. УПРАВЛЯЮШИЕ КОНСТРУКЦИИ
71.1.1.1. УСЛОВНЫЕ ОПЕРАТОРЫ
71.1.1.2. ОПЕРАТОРЫ СЕЛЕКЦИИ
71.1.1.3. ЦИКЛЫ
71.1.1.3.1. ИТЕРАТОРЫ
71.1.1.3.2. ПАРАЛЕЛЬНЫЕ ЦИКЛЫ
71.1.2. ПРОЦЕДУРЫ И ФУНКЦИИ
71.1.2.1. ФУНКЦИИ С ПЕРЕМЕННЫМ ЧИСЛОМ АРГУМЕНТОВ
71.1.3. ТИПЫ ДАННЫХ И КОНСТАНТЫ
71.1.4. ОПЕРАЦИИ
71.1.4.1. ПЕРЕГРУЗКА ОПЕРАЦИЙ
71.1.5. ОБЪЕКТЫ
71.1.5.1. ПРЕОБРАЗОВАНИЯ ТИПОВ
71.1.6. МОДУЛИ
71.1.7. ИСКЛЮЧЕНИЯ
71.1.8. МАКРОКОНСТРУКЦИИ
71.1.9. ПРОСТРАНСТВА ИМЕН
71.1.10. ШАБЛОНЫ
71.1.11. RTTI (RUN TIME TYPE INFORMATION)
71.2. ДЕКЛАРАТИВНЫЕ ЯЗЫКИ ПРОГРАММИРОВАНИЯ
71.3. ЯЗЫКИ УПРАВЛЯЕМЫЕ ПОТОКОМ ДАННЫХ
71.4. ЯЗЫКИ ОПИСАНИЯ ОБОРУДОВАНИЯ
71.5. ПРОБЛЕМНО-ОРИЕНТИРОВАННЫЕ ЯЗЫКИ СВУ
71.6. ABI (APPLICATION BINARY INTERFACE)
71.6.1. КОНВЕНЦИИ ВЫЗОВОВ
70.50. ТЕОРИЯ ВЫЧИСЛЕНИЙ
70.50.1. ГРАММАТИКИ
70.50.2. АВТОМАТЫ
70.50.3. НФБН
70.50.3. ЛЕКСИЧЕСКИЙ АНАЛИЗ
70.50.4. СИНТАКСИЧЕСКИЙ АНАЛИЗ

СЖАТИЕ ДАННЫХ И КОЛОРМЕТРИЯ

72.1. СЖАТИЕ ДАННЫХ
72.1.1. ТЕОРИЯ ИНФОРМАЦИИ
72.1.2. СЛОВАРНОЕ СЖАТИЕ
72.1.3. ЧАСТОТНОЕ СЖАТИЕ
72.1.3.1. ПРЕОБРАБОТКА ИНФОРМАЦИИ ДЛЯ СЖАТИЯ
72.1.4. СЖАТИЕ ДАННЫХ С ПОТЕРЯМИ
72.1.4.1. СПЕКТР И ПРЕОБРАЗОВАНИЕ ФУРЬЕ
72.1.4.2. КОЛОРМЕТРИЯ
72.1.4.3. JPEG
72.1.4.4. MPEG
72.1.4.5. ВЕЙВЛЕТЫ
72.1.4.6. ФРАКТАЛЬНОЕ СЖАТИЕ
72.1.4.7. MP3 (MPEG1 LAYER 3)

КРИПТОГРАФИЯ

72.2. КРИПТОГРАФИЯ
72.2.2. ШИФРОВАНИЕ С ЗАКРЫТЫМ КЛЮЧЕМ
72.2.3. ШИФРОВАНИЕ С ОТКРЫТЫМ КЛЮЧЕМ
72.2.4. АУТЕНТИФИКАЦИЯ
72.2.4.1. ОБМЕН КЛЮЧАМИ
72.2.4.2. АЛГОРИТМ НИДХЕМА-ШРЕДЕРА
72.2.4.3. KERBEROS
72.2.5. ХЭШИ И ЦИФРОВАЯ ПОДПИСЬ
72.2.5.1. ЦИФРОВОЙ КОНВЕРТ
72.2.5.2. ЦИФРОВЫЕ СЕРТИФИКАТЫ
72.2.6. ДОВЕРЕННОЕ БРОСАНИЕ МОНЕТЫ
72.2.7. КВАНТОВАЯ КРИПТОГРАФИЯ
72.2.8. АЛГОРИТМ ШОРА
72.2.9. АЛГОРИТМ ЕВКЛИДА
72.50. НЕКОТОРЫЕ СВЕДЕНИЯ ИЗ ТЕОРИИ ВЕРОЯТНОСТИ

КОМПЬЮТЕРНАЯ ГРАФИКА

73. КОМПЬЮТЕРНАЯ ГРАФИКА
73.1. ДВУМЕРНАЯ КОМПЬЮТЕРНАЯ ГРАФИКА
73.2. КЛЕТОЧНЫЕ АВТОМАТЫ
73.3. АФФИННЫЕ ПРЕОБРАЗОВАНИЯ
73.4. МОДЕЛИРОВАНИЕ
73.5. ОСНОВЫ ЛИНЕЙНОЙ АЛГЕБРЫ ИТД
73.6. ИГРА ЖИЗНЬ

ИСКУСТВЕННЫЙ ИНТЕЛЛЕКТ

75. ПОДХОДЫ К AI
75.1. ОБУЧЕНИЕ
75.2. НЕЧЕТКАЯ ЛОГИКА
75.3. НЕЙРОННЫЕ СЕТИ
75.4. ПРОСТРАНСТВО СОСТОЯНИЙ
75.5. ГЕНЕТИЧЕСКИЕ АЛГОРИТМЫ
75.6. DATA MINING

ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ

80. ПРОГРАМНОЕ ОБЕСПЕЧЕНИЕ
80.1.1. BIOS
80.1.2. ДРАЙВЕРЫ
80.1.2.1.1. КОНФИГУРИРОВАНИЕ ШИН
80.1.2.1.1.1. PnP КОНФИГУРИРОВАНИЕ
80.1.2.1.2. РАБОТА ДРАЙВЕРОВ С ПРЕРЫВАНИЯМИ
80.1.2.1.3. РАБОТА ДРАЙВЕРОВ С ПАМЯТЬЮ
80.1.2.1.4. РАБОТА ДРАЙВЕРОВ С ПРОСТРАНСВОМ ИМЕН И ИНФРАСТРУКТУРА
80.1.2.2.1. STORAGE DRIVERS
80.1.2.2.2. FILESYSTEM DRIVERS
80.1.2.2.3. NETWORKS DRIVERS
80.1.3. ОПЕРАЦИОННЫЕ СИСТЕМЫ
80.1.3.1. НИТИ И МНОГОЗАДАЧНОСТЬ
80.1.3.1.1. REAL TIME SCHEDULING
80.1.3.2. ПРОЦЕССЫ И УПРАВЛЕНИЕ ВИРТУАЛЬНОЙ ПАМЯТЬЮ
80.1.3.3. ПРОГРАММЫ
80.1.3.4. ДИНАМИЧЕСКИЕ БИБЛИОТЕКИ
80.1.3.5. TLS (THREAD LOCAL STORAGE)
80.1.3.6. СТРУКТУРЫ НИТЕЙ/ПРОЦЕССОВ НА ПРИМЕРАХ
80.1.3.7. СТРУКТУРЫ СИНХРОНИЗАЦИИ
80.1.3.8. IPC
80.1.3.9. КЛАСТЕРЫ
80.1.3.10.1. ФАЙЛОВЫЕ СЕРВИСЫ ОПЕРАЦИОННЫХ СИСТЕМ
80.1.3.10.2. СЕТЕВЫЕ СРЕДСТВА ОПЕРАЦИОННЫХ СИСТЕМ
80.1.4. ИНСТРУМЕНТЫ РАЗРАБОТКИ
80.1.4.1. ОБЩЕЕ УСТРОЙСТВО КОМПИЛЯТОРОВ
80.1.4.1.1. ОПТИМИЗАЦИИ ВНУТРИ КОМПИЛЯТОРОВ
80.1.4.1.2. ТИПОВЫЕ ВНУТРЕННИЕ СТРУКТУРЫ КОМПИЛЯТОРОВ
80.1.4.2. АССЕМБЛЕРЫ
80.1.4.3. ЛИНКЕРЫ
80.1.4.4. MAKE
80.1.4.5. КОНТРОЛЬ ВЕРСИЙ
80.2.1. БАЗЫ ДАННЫХ
80.3.1. КАК РАБОТАЕТ BROWSER?
80.3.2. КАК РАБОТАЕТ ТЕКСТОВЫЙ РЕДАКТОР?
80.3.3. КАК РАБОТАЕТ ТЕКСТОВЫЙ ПРОЦЕССОР?
80.3.4. КАК РАБОТАЕТ ГРАФИЧЕСКИЙ РЕДАКТОР?
80.3.5. КАК РАБОТАЕТ СИСТЕМЫ ВЕРСТКИ
80.3.6. КАК РАБОТАЮТ ЭЛЕКТРОННЫЕ ТАБЛИЦЫ
80.3.7. КАК РАБОТАЕТ OCR?

ОСНОВНЫЕ ПОДСИСТЕМЫ ОПЕРАЦИОННЫХ СИСТЕМ

81. ОСНОВНЫЕ ПОДСИСТЕМЫ
81.1. ПОДСИСТЕМА ВРЕМЕНИ
81.1.1. API ДЛЯ РАБОТЫ СО ВРЕМЕНЕМ
81.1.1. ПОСТРОЕНИЕ ОЧЕРЕДЕЙ СВЯЗАННЫХ СО ВРЕМЕНЕМ
81.1.2. ТАЙМЕРЫ
81.1.3. КЛАССЫ ДЛЯ РАБОТЫ С ВРЕМЕНЕМ
81.1.4. ИНФОРМАЦИЯ О TIME ZONES
81.2. ПОДСИСТЕМА ПАМЯТИ
81.2.1. ФИЗИЧЕСКАЯ ПАМЯТЬ
81.2.1.1. КЭШИРОВАНИЕ ФИЗИЧЕСКОЙ ПАМЯТИ
81.2.2. ПРИМИТИВЫ РАБОТЫ С ПАМЯТЬЮ
81.2.2.1. ПАРАЛЕЛЬНЫЕ АЛГОРИТМЫ НАД ПАМЯТЬЮ
81.2.3. КУЧИ: ОРГАНИЗАЦИЯ И РАБОТА
81.2.3.1. СЛАБОВЫЕ АЛЛОКАТОРЫ
81.2.3.2. ОКОНЕЧНЫЕ ЯЗЫКОВЫЕ ИНТЕРФЕЙСЫ РАБОТЫ С ПАМЯТЬЮ
81.2.3.2.1. БОРЬБА С УТЕЧКАМИ ПАМЯТИ
81.2.4. ПАМЯТЬ С ТОЧКИ ЗРЕНИЯ ПРИЛОЖЕНИЙ
81.2.5. ОРГАНИЗАЦИЯ ВИРТУАЛЬНОЙ ПАМЯТИ НА X86
81.2.6. ПАМЯТЬ С ТОЧКИ ЗРЕНИЯ ДРАЙВЕРОВ И ОПЕРАЦИОННОЙ СИСТЕМЫ
81.2.7. СТРУКТУРНАЯ ОРГАНИЗАЦИЯ ПАМЯТИ В ОПЕРАЦИОННЫХ СИСТЕМАХ
81.2.8. МЕХАНИКА СТОЯЩАЯ ЗА ОБРАЩЕНИЯМИ К СТРАНИЦАМ
81.2.8. ДЕЙСТВИЯ ОПЕРАЦИОННОЙ СИСТЕМЫ
81.2.9. ОКНА ПАМЯТИ
81.2.10. RTL ДЛЯ ПАМЯТИ
81.3. ФАЙЛОВАЯ И STORAGE ПОДСИСТЕМА
81.3.1. STORAGE УСТРОЙСТВА
81.3.1.1. СТРУКТУРА ДИСКОВЫХ НОСИТЕЛЕЙ
81.3.1.2. ТИПОВЫЕ КОМАНДЫ STORAGE DEVICES
81.3.1.3. СПЕЦИАЛЬНЫЕ FEATURES НА КОТОРЫЕ НАДО ОБРАТИТЬ ОСОБОЕ ВНИМАНИЕ
81.3.1.4. ДРАЙВЕРА STORAGE CONTROLLERS
81.3.1.5. ФИЛЬТРЫ STORAGE CONTROLLER ДРАЙВЕРОВ
81.3.1.6. SCSILIZER
81.3.1.7. DISK SCHEDULING
81.3.1.8. ФИЗИЧЕСКОЕ КЭШИРОВАНИЕ
81.3.1.8.1. MULTIPATH I/O
81.3.1.9. УРОВЕНЬ ФИЗИЧЕСКОГО ДИСКА
81.3.1.10. ТИПОВЫЕ СЦЕНАРИИ ПРИ РАБОТЕ С ДИСКОВЫМИ УСТРОЙСТВАМИ
81.3.1.11. УРОВЕНЬ ПАРТИЦИЙ
81.3.1.12. УРОВЕНЬ SOFTWARE RAIDs
81.3.1.13. УРОВЕНЬ ЛОГИЧЕСКОГО ДИСКА
81.3.1.14. ФИЛЬТРАЦИЯ БЛОЧНЫХ УСТРОЙСТВ
81.3.1.15. DISK ARBITRATION
81.3.1.50. ОСОБЕННОСТИ РАБОТЫ С ОПТИЧЕСКИМИ НАКОПИТЕЛЯМИ
81.3.1.50. ОСОБЕННОСТИ РАБОТЫ С MEDIA CHANGERS (JUKEBOX)
81.3.1.51. ОСОБЕННОСТИ РАБОТЫ С ЛЕНТОЧНЫМ STORAGE
81.3.2.0. ОРГАНИЗАЦИЯ ФАЙЛОВЫХ СИСТЕМ
81.3.2.0.0. СТАНДАРТНЫЕ СВОЙСТВА ОБЪЕКТОВ ФАЙЛОВОЙ СИСТЕМЫ
81.3.2.0.1. ОБЪЕКТЫ ФАЙЛОВЫХ СИСТЕМ
81.3.2.0.2. ДИСКОВЫЕ КВОТЫ
81.3.2.0.3. СПЕЦИАЛЬНЫЕ СВОЙСТВА ФАЙЛОВЫХ СИСТЕМ
81.3.2.1. VFS LAYER
81.3.2.1.1. БЛОКИРОВКА ФАЙЛОВ
81.3.2.2. CACHE MANAGER
81.3.2.3. ВИРТУАЛЬНОЕ КЭШИРОВАНИЕ
81.3.2.4. FILESYSTEM FILTER DRIVERS
81.3.2.5. FILE SYSTEM DRIVERS (FSD)
81.3.2.5.1. FILESYSTEM ABILITIES
81.3.2.6. АВТОМОНТИРОВАНИЕ - КАК ЭТО РАБОТАЕТ?
81.3.2.7. ДИНАМИЧЕСКОЕ ИЗМЕНЕНИЕ РАЗМЕРА ТОМА
81.3.2.8. ПОДДЕРЖКА СОЗДАНИЯ СНАПШОТОВ СО СТОРОНЫ FSD
81.3.2.9. ОБСЛУЖИВАНИЕ ФАЙЛОВОЙ СИСТЕМЫ
81.3.3. API ОПЕРАЦИОННЫХ СИСТЕМ ДЛЯ РАБОТЫ С ФАЙЛАМИ И ФАЙЛОВЫМИ СИСТЕМАМИ
81.3.3.1. КОРНЕВЫЕ И НЕКОРНЕВЫЕ ФАЙЛОВЫЕ ПОДСИСТЕМЫ
81.3.3.2. ТОМА ФАЙЛОВОЙ СИСТЕМЫ
81.3.3.3. ФАЙЛЫ
81.3.3.4. API РАБОТЫ С ФАЙЛАМИ
81.3.3.4.1. РАБОТА С БОЛЬШИМИ ФАЙЛАМИ
81.3.3.4.2. MEMORY-MAPPED ФАЙЛЫ
81.3.3.5. КОНЦЕПТУАЛЬНЫЙ RTL РАБОТЫ С ФАЙЛАМИ
81.3.3.6. ДИРЕКТОРИИ
81.3.3.7. ТРАНЗАКЦИОННЫЕ ОПЕРАЦИИ
81.3.3.8. QOS ДЛЯ ФАЙЛОВОГО ВВОДА/ВЫВОДА
81.3.3.9. ОШИБКИ ПРИ РАБОТЕ С ФАЙЛАМИ
81.3.4.1. РАБОТА С ПУТЯМИ
81.3.4.2. ПОЛЕЗНЫЕ ОПЕРАЦИИ КОТОРЫЕ НЕ ПОДДЕРЖИВАЮТСЯ ФАЙЛОВЫМИ СИСТЕМАМИ НА ПРЯМУЮ
81.3.4.3. СТАНДАРТНЫЕ БИБЛИОТЕКИ ДЛЯ РАБОТЫ С ФАЙЛАМИ
81.3.4.4. ТИПОВЫЕ КЛАССЫ ДЛЯ РАБОТЫ С ФАЙЛОВОЙ СИСТЕМОЙ
81.3.5. ВОПРОСЫ ENTERPRISE STORAGE
81.4. СЕТЕВАЯ ПОДСИСТЕМА
81.4.1. ОБЩАЯ АРХИТЕКТУРА СЕТЕВОЙ ПОДСИСТЕМЫ
81.4.1.0. СЕТЕВАЯ КАРТА ETHERNET
81.4.2. ИНТЕРФЕЙСЫ ДРАЙВЕРОВ ФИЗИЧЕСКИХ УСТРОЙСТВ
81.4.3. СЕТЕВЫЕ ОКРУЖЕНИЯ
81.4.3.1. БЫСТРЫЙ FORWARDING НА УРОВНЕ NETWORK ENVIRONMENT
81.4.4. INTERMEDIATE DRIVERS
81.4.5. ИНТЕРФЕЙСЫ ДРАЙВЕРОВ СЕТЕВЫХ ПРОТОКОЛОВ
81.4.5.1. ТРАНКИНГ
81.4.6. РАЗРЕШЕНИЕ ЛОКАЛЬНЫХ АДРЕССОВ
81.4.7. ROUTING
81.4.8. FILTER DRIVERS
81.4.9. QoS
81.4.10. NAT
81.4.11. ТУНЕЛИРОВАНИЕ И VPN
81.4.11.1. MOBILITY
81.4.12. SOCKET PROVIDER
81.4.12.1. СТРУКТУРЫ ПРОТОКОЛЬНЫХ АДРЕСОВ ДЛЯ ИНТЕРФЕЙСА СОКЕТОВ
81.4.13. РАЗРЕШЕНИЕ ИМЕН
81.4.14. ПОЛЬЗОВАТЕЛЬСКИЕ API ДЛЯ СЕТЕВЫХ КОММУНИКАЦИЙ
81.4.14.1. API ДЛЯ РАБОТЫ С MULTICAST
81.4.14.2. API ДЛЯ РАБОТЫ С QoS
81.4.15. ПОЛЬЗОВАТЕЛЬСКИЕ API ДЛЯ УПРАВЛЕНИЯ СЕТЬЮ
81.4.15.1. УПРАВЛЕНИЕ СЕТЕВЫМИ ИНТЕРФЕЙСАМИ
81.4.15.2. РАЗРЕШЕНИЕ ЛОКАЛЬНЫХ АДРЕССОВ
81.4.15.3. УПРАВЛЕНИЕ ЛОКАЛЬНЫМИ АДРЕССАМИ
81.4.15.4. УПРАВЛЕНИЕ МАРШРУТИЗАЦИЕЙ
81.4.15.5. УПРАВЛЕНИЕ КОНКРЕТНЫМИ ПРОТОКОЛАМИ
81.4.16. СЕТЕВЫЕ СЕРВИСЫ
81.4.17. ПРИМЕРЫ КЛАССОВ ДЛЯ РАБОТЫ С СЕТЬЮ
81.5. УПРАВЛЕНИЕ ПОТОКАМИ И ПРОЦЕССАМИ
81.5.0. ГРУППЫ ПРОЦЕССОВ
81.5.1. ПРОЦЕССЫ
81.5.1.1. КОММАНДНАЯ СТРОКА
81.5.1.2. ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ
81.5.1.3. HANDLES И HANDLE MANAGEMENT
81.5.1.4. APC (APPLICATION SPECIFIC CALLBACKS)
81.5.2. ПОТОКИ
81.5.2.1. ПУЛЫ ПОТОКОВ
81.5.2.2. ВОЛОКНА
81.5.3. IPC
81.5.4. ОТЛАДКА
81.5.5. ФОРМАТЫ ИСПОЛНЯЕМЫХ ФАЙЛОВ
81.5.6. ОПРЕДЕЛЕНИЕ ВЕРСИИ ОПЕРАЦИОННОЙ СИСТЕМЫ
81.5.7. СТАНДАРТНЫЕ БИБЛИОТЕКИ
81.6. ЗАДАЧИ ПОДИСТЕМА БЕЗОПАСНОСТИ
81.6.1. ACL (ACCESS CONTROL LISTS)
81.6.1.1. SECURITY ID
81.6.2. АУФЕНТИКАЦИЯ
81.6.2.1. БИОМЕТРИЯ
81.6.3. ИМПЕРСОНАЦИЯ
81.6.4. АУДИТ
81.6.5. ПРИВИЛЕГИИ
81.6.6. ACCOUNT MANAGEMENT
81.7. УПРАВЛЕНИЕ КОНСОЛЬЮ
81.8. ПОДСИСТЕМА GUI
81.8.1. ОКНА
81.8.2. СООБЩЕНИЯ
81.8.3. WIDGETS
81.8.3.1. МЕНЕДЖЕРЫ ПАКОВКИ ВИДЖЕТОВ
81.8.4. MENU
81.8.5. АБСТРАКЦИЯ DEVICE CONTEXT И СИСТЕМЫ КООРДИНАТ
81.8.6. ПРИМИТИВЫ РИСОВАНИЯ
81.8.10. ШРИФТЫ
81.8.11. ФОРМАТЫ ГРАФИЧЕСКИХ ФАЙЛОВ
81.8.20. ГРАФИЧЕСКАЯ АКСЕЛЕРАЦИЯ
81.9. ПОДСИСТЕМА ЗВУКА
81.9.10. ФОРМАТЫ ЗВУКОВЫХ ФАЙЛОВ
81.10. УПРАВЛЕНИЕ ПЕРЕФИРИЙНЫМИ УСТРОЙСТВАМИ
81.10.1. ПОСЛЕДОВАТЕЛЬНЫЙ ПОРТ
81.10.2. ПАРАЛЕЛЬНЫЙ ПОРТ
81.10.3. ПЕЧАТЬ
81.10.4. СКАНИРОВАНИЕ
81.10.5. REAL TIME ВИДЕО-ВВОД
81.10.6. CUSTOM USB УСТРОЙСТВА

СИНХРОНИЗАЦИЯ

82. СИНХРОНИЗАЦИЯ
82.1. ПРИМИТИВЫ СИНХРОНИЗАЦИИ
82.2. ПРОБЛЕМЫ СИНХРОНИЗАЦИИ
82.3. СТАНДАРТНЫЕ БИБЛИОТЕКИ ДЛЯ СИНХРОНИЗАЦИИ

UNDER CONSTRUCTION

83. MIDDLEWARE

СЕТЕВЫЕ ПРОТОКОЛЫ

84. СЕТЕВЫЕ ПРОТОКОЛЫ
84.1. ПРОТОКОЛЫ СЕТЕВОЙ ИНФРАСТРУКТУРЫ
84.1.1. РАЗРЕШЕНИЕ ЛОКАЛЬНЫХ АДРЕССОВ
84.1.2. РАЗРЕШЕНИЕ ИМЕН
84.1.3. ПОЛУЧЕНИЕ СЕТЕВЫХ АДРЕССОВ
84.1.4. ROUTING ПРОТОКОЛЫ
84.1.5. ПРОТОКОЛЫ ТУННЕЛИРОВАНИЯ
84.1.5. ПРОТОКОЛЫ УПРАВЛЕНИЯ СЕТЬЮ
84.1.6. QUALITY OF SERVICES (QoS) ПРОТОКОЛЫ
84.1.7. MOBILITY ПРОТОКОЛЫ
84.1.8.PROXY ПРОТОКОЛЫ
84.2. ПРИКЛАДНЫЕ ПРОТОКОЛЫ
84.2.1. ПРОТОКОЛЫ ЭЛЕКТРОННОЙ ПОЧТЫ
84.2.2. ПРОТОКОЛЫ НОВОСТЕЙ
84.2.3. ПРОТОКОЛЫ ТЕРМИНАЛЬНОГО ДОСТУПА
84.2.4. ПРОТОКОЛЫ ГРАФИЧЕСКИХ ТЕРМИНАЛОВ
84.2.5. ПРОТОКОЛЫ ПЕРЕДАЧИ ФАЙЛОВ
84.2.6. ПРОТОКОЛЫ СЕТЕВЫХ ФАЙЛОВЫХ СИСТЕМ (NAS)
84.2.7. STORAGE AREA NETWORK ПРОТОКОЛЫ (SAN)
84.2.8. ПРОТОКОЛЫ ДЛЯ ВРЕМЕНИ
84.2.9. WEB
84.2.9.1.1. ПРОТОЛЫ ПЕРЕДАЧИ ДАННЫХ WEB
84.2.9.1.2. ЯЗЫК РАЗМЕТКИ HYPERTEXT
84.2.9.1.3. DYNAMIC HTML
84.2.9.1.4. ПОДДЕРЖКА НА СТОРОНЕ СЕРВЕРА
84.2.9.1.5. AJAX
85.2.9.2. КОНТЕКСТНАЯ ЧАСТЬ WEB
84.2.10. ПРОТОКОЛЫ ДЛЯ ЧАТА
84.2.11. DIRECTORY SERVICES ПРОТОКОЛЫ
84.2.12. ПРОТОКОЛЫ ПЕЧАТИ
84.2.13. ФАЙЛООБМЕННЫЕ ПРОТОКОЛЫ
84.2.14. ПРОТОКОЛЫ ТОРГОВЛИ
84.2.15. ПРОТОКОЛЫ ПОТОКОВОГО MULTIMEDIA
84.2.16. ЗАГРУЗОЧНЫЕ ПРОТОКОЛЫ

DEVELOPMENT

90. ИСКУССТВО УПРАВЛЕНИЯ

ПРОЧИЕ ТЕХНОЛОГИИ

99. ДРУГИЕ ТЕХНОЛОГИИ
99.1. ПНЕВМОНИКА
99.2. РЕЛЕЙНАЯ ЛОГИКА
99.3. ЭЛЕКТРОННЫЕ ЛАМПЫ
99.3.1. ПАМЯТЬ НА ФЕРИТОВЫХ СЕРДЕЧНИКАХ
99.3.2. ВНЕШНЯЯ ПАМЯТЬ НА МАГНИТНЫХ БАРАБАНАХ
99.4. DL
99.5. RTL
99.6. DTL
99.8. РЕАЛИЗАЦИЯ ТРОИЧНОЙ ЛОГИКИ
99.9. ОПТИЧЕСКИЕ ВЫЧИСЛЕНИЯ
99.10. КВАНТОВЫЕ ВЫЧИСЛЕНИЯ
99.11. ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ НА ЭФФЕКТЕ ДЖОЗЕФСОНА

OUTRO

100. TESTBENCH
100.1. ГЕНЕРАЦИЯ CLK СИГНАЛА
100.2. ГЕНЕРАЦИЯ СИГНАЛА RESET
100.3. TESTBENCH ДЛЯ РЕАЛЬНОЙ ЖИЗНИ
200. ЗАДАЧИ И УПРАЖНЕНИЯ
200.1. ЗАДАЧИ К ВВЕДЕНИЮ (1.X)
200.2. ЗАДАЧИ К БУЛЕВОЙ АЛГЕБРЕ (2.X)
200.3. ЗАДАЧИ К СИСТЕМАМ СЧИСЛЕНИЯ (3.X)
200.4. ЗАДАЧИ К ПРОЧИМ СЕКЦИЯМ
300. СПИСОК ЛИТЕРАТУРЫ
401. ДОПОЛНИТЕЛЬНАЯ ОБЩАЯ ИНФОРМАЦИЯ
402. SOFTWARE
403. PHG
404. ОБ АВТОРЕ