Compare commits

..

20 Commits

Author SHA1 Message Date
08ef56179a feat(09): Добавлены схемы кэшей 2025-01-08 13:29:11 +03:00
45ed47ce89 feat(09): Написаны разделы про организацию и виды кэша 2025-01-08 01:16:07 +03:00
1b7a10d5bd feat: существенно расширил contributing и изменил порядок работы
поскольку штат людей, которые пишут билеты расширился, возникла необходимость стандартизировать порядок внесения вклада
2025-01-06 23:27:22 +03:00
0c9a61e05a chore: убрал тег "в процессе", добавил временный тег
тег "доработать" нужен, чтобы показать, что я все еще принимаю критику по этому билету
2025-01-06 01:06:03 +03:00
d10401ed01 feat: билет 4 доведен до какого-то состояния 2025-01-06 01:04:34 +03:00
870a2efa6e feat: дополнен конспект по 3 главе
В новой информации все, что требуется для билета 4
2025-01-05 23:45:50 +03:00
086244536e feat: 3 билет написан 2025-01-02 00:57:15 +03:00
9302adef05 chore: добавлены теги "устарело"
После обновления списка вопросов, оказалось, что препод решил расширить темы, по которым он опрашивает, поэтому уже написанные билеты пришлось пометить как устаревшие. Метка будет убрана после их приведения к актуальному состоянию
2025-01-02 00:16:54 +03:00
ba300b1911 chore: убрал тег "в процессе" 2025-01-01 22:03:18 +03:00
6261f45cd9 chore: изменил теги 2024-11-10 00:53:23 +03:00
a2dc72a3f4 useless: почему-то гит видит тут изменения 2024-11-10 00:50:57 +03:00
1875ea37e5 feat: минимальный второй билет написан 2024-11-10 00:48:30 +03:00
717bcf2c06 fix: исправлен тег 2024-11-09 23:58:17 +03:00
e9f9652be8 feat: расписал MPEG и M-JPEG 2024-11-09 23:56:38 +03:00
50c2b4b54d feat: подробнее описан JPEG 2024-11-09 18:26:32 +03:00
0b109f4d81 fix: улучшил объяснения и исправил несколько опечаток 2024-11-09 16:46:05 +03:00
63e0ef13e6 fix: добавил недостающие конспекту изображения 2024-11-06 21:50:19 +03:00
547febcb51 feat: информация по алгоритмам сжатия без потерь 2024-11-06 21:49:07 +03:00
1dad8630fd feat: добавлена сноска 2024-11-05 17:30:00 +03:00
f7bdc49acd docs: расширен раздел использования 2024-11-05 17:29:32 +03:00
37 changed files with 825 additions and 10 deletions

View File

@ -4,15 +4,92 @@ tags:
---
# Соглашения о вкладе
## Стиль билетов
> [!attention]+ Основное требование к билету
>**НЕ ПРОСТО ПЕРЕПИСЫВАЙТЕ МЕТОДИЧКУ СЛОВО В СЛОВО**: старайтесь ужать материал и сделать его как можно понятнее
*Иначе смысла в написании билетов нет ни для вас, ни для человека, который может их почитать. Разбиение методички на билеты - не самая важная часть нашей деятельности*
При написании билетов я предполагаю, что пользователь сидит в режиме чтения
### Объем билетов
Довольно очевидно, что билеты должны быть максимально короткими, чтобы человек не учил то, что может не учить, но при этом они не должны быть невнятными. Старайтесь выдерживать золотую середину между читаемостью и объемом
Периодически в билете требуется пояснить моменты, которые вообще говоря не надо запоминать и они не связаны с ответом, но они помогают пониманию билета. В таком случае я обычно пишу что-то вроде:
> [!comment]- Примечание билетера о ...
> Какое-то пояснение, которое я считаю важным дать, но которое не важно во время ответа
Оформляется оно при помощи коллаутов примерно так:
```md
> [!comment]- Примечание билетёра о ...
> lorem ipsum dolor sit amet
```
Также считаю допустимым использование примечаний^[Это примечание отобразится в конце страницы и не будет так сильно отвлекать от билета]. Они автоматически складываются в конце страницы и при наведении на них всплывает подсказка, что тоже довольно удобно для пояснений
## Шаблоны
У нас есть 2 шаблона. Фактически стандартизируют они только подложку заметки:
- Билет - содержит поля под:
- теги
- [[#Закон каламбура|каламбур]]
- автора (указываете свой ник или как вам удобно представиться)
- ревизию (это поле для ElectronixTM, потому что его попросили верифицировать все написанное. Он укажет туда информацию о ревизии)
- Заметка - просто любая заметка на ваш вкус, которая может содержать дополнительную информацию, которая не идет в билеты. Для первых 4 билетов в таких написаны конспекты некоторых разделов билетов
## Дирректории
В проекте у нас есть главная папка: "Билеты". Пояснять, думаю, не надо, а также папка: "Дополнительно". В папку дополнительно идет все, что только пожелаете. В этой папке есть еще и digital garden - можете погуглить "второй мозг", "zettelkasten" и "commonplace". У меня была идея с этим что-то придумать, но как бы не вышло, но может вы захотите хранить такие вот атомизированные заметки в каком-то месте
## Именование файлов
Все названия файлов подчиняются следующему шаблону: `xx - название`. Тут все стандартно как с физикой
## Ветки
Так как я больше не один, надо бы по веточкам работать. Именование веток довольно произвольное. Обойдемся стандартным набором, только модифицируем его:
- `feat` - под всё новое
- `feat/tickets/xx` - Написание нового билета должно проходить именно в таких ветках
- `fix` - какие-то исправления в уже написанном материале
- `other` - все, что не подвязывается к первым двум
Пул реквесты можете делать, но тогда сразу назначайте человека, который будет вас проверять, а потом желательно сразу же ему писать в личку (благо все свои). Если что, можете сразу мерджить изменения в мастер, тут расчет на вашу адекватность
## Коммиты
Тут все по стандарту conventional commits. Все сообщения к коммитам пишутся на русском, с маркерами:
1. `feat` - сделал что-то новое
2. `fix` - починил что-то старое
3. `chore` - убирание тегов, изменение названий, в общем всякая мелочь
### Примеры
- `feat: написал конспект 3 главы 3.2 раздела`
- `chore: удалил тег "в процессе"`
*Просьба просто в том, чтобы человек не открывая коммит мог получить представление о том, что вы там сделали, так что не надо чего-то вроде: fix, fix, fix, fix*
## Разрешенные плагины для Obsidian
В [[README]] я уже говорил, что все билеты пишутся под Obsidian, а поскольку он поддерживает разные плагины, есть соблазн поставить парочку. В связи с этим регулировка такая:
- Разрешены любые плагины до тех пор, пока все, что вами написано, нормально рендерится в ванильном обсидиане без единого плагина.
Может закон и не точный, но и мы не на уроке права, поэтому поясню мысль и буду надеяться на благоразумие:
Мы уже предъявляем определенные требования к пользователю - он должен открывать этот проект непременно в обсидиане. Так давайте же уважим его и не будем заставлять еще и скачивать плагины
## Использование тегов
Я отхожу от своей классической практики помечать тегами только служебную информацию о заметках и даю возможность использовать предметные теги на свое усмотрение на следующих условиях:
- Обязательно проверьте, какие теги уже существуют. Сделать это можно при помощи скрипта, который тут приложен
- Обязательно проверьте, какие теги уже существуют
- Есть небольшой набор служебных тегов, которые призваны помогать искать недоделки и недоработки
### Стиль тегов
@ -22,15 +99,19 @@ tags:
- `#математика`
- `#русский_язык`
Также Obsidian из коробки поддерживает вложенные теги: `#это/пример/вложенного/тега`
ограничения те же, что и на все остальные теги
### Служебные теги
Все служебные заметки начинаются со специальной комбинации `#служебные/`
Все служебные заметки начинаются со специальной комбинации `#служебное/`
- #служебное/доработать - заметка в целом закончена, но нужно внести некоторые доработки
- #служебное/в_процессе - заметка по каким-то причинам отложена и не закончена
- #служебное/в_процессе - заметка еще пишется, а это промежуточный результат работы
- #служебное/устарело - Препод поменял билеты, поэтому то, что было написано, не совсем актуально. Все, что не актуально, и еще не пересмотрено помечается деприкейтится этой меткой
Эти теги служат только для передачи служебной информации о состоянии заметки
## Политика каламбуров
## Закон каламбура
Каждый билет должен сопровождаться каламбуром. Эти каламбуры вставляются в подложку заметки
Каждый билет должен сопровождаться каламбуром. Эти каламбуры вставляются в подложку заметки. Тема не важна, но это должен быть обязательно **каламбур**

View File

@ -6,7 +6,9 @@
## Использование
Эти билеты пишутся так, чтобы их легко мог прочитать obsidian. В будущем возможно добавлю сборку в PDF если мне будет нечего делать
Эти билеты пишутся так, чтобы их легко мог прочитать obsidian. В будущем возможно добавлю сборку в PDF если мне будет нечего делать. Для начала работы склонируйте данный репозиторий себе на устройство и откройте его корневую директорию (ту, в которой лежит этот файл) как хранилище Obsidian (Obsidian vault).
Вы также можете вмонтировать этот репозиторий в уже существующее хранилище. В таком случае не могу гарантировать отсутствие пересечений, но вполне вероятно, что у вас все будет хорошо
### Примечание

View File

@ -1,6 +1,6 @@
---
tags:
- служебное/в_процессе
- служебное/устарело
pun: Штирлиц был у окна, а из окна дуло. Штирлиц встал, дуло убрали
---
<!--Поскольку в целом напрямую на этот вопрос отвечено в конспекте, позволю себе в лоб вставить кусок из него-->
@ -12,7 +12,7 @@ pun: Штирлиц был у окна, а из окна дуло. Штирли
*Чуть больше гугла и доверия к рандомным сайтам*
1. Параллелизм - фон Неймановская архитектура изначально была простой и должна оставаться простой. Предположить кучи потоков ученые тогда не могли
2. Кэш память для x86-х интелов строится на Гарвардской архитектуре, что позволяет хотя бы сколько-то оптимизировать бутылочное горлышко, созданное фон Нейманом
2. Кэш память для x86-х интелов строится на Гарвардской архитектуре, что позволяет хотя бы сколько-то оптимизировать "бутылочное горлышко"[^bootle-neck], созданное фон Нейманом
3. Если верить [рандомному человеку из интернета](https://arch32.cs.msu.ru/Text/Chapter_02.pdf), то изначально устройства ввода (клава, мышь, USB и прочие) передавали данные не напрямую в память, а обращались к АЛУ. То есть в момент нажатия на клавишу на клавиатуре вся машина приостанавливала свою работу лишь бы обработать твою кнопочку. *Сейчас ситуация сходная, но все же процессор вылетает в прерывание когда ему это удобно и обрабатывает прерывание по тому, что уже лежит в памяти*
4. Современная оператива уже не очень однородна.
1. В общем случае она довольно долго может искать место начала, но когда найдет, быстро читает из него по 64 байта например. Это сделано для оптимизации узкого горлышка все архитектуры, потому что через шину адреса, нашу ахилесову пяту, гоняется вообще вся информация - очередная команда, адреса, сами данные и прочая. И тот факт, что шина позволяет обменяться с процессором только одним машинным словом (не путайте с WORD в ассемблере, тут имеется в виду размер слова равный размеру адреса)
@ -22,4 +22,6 @@ pun: Штирлиц был у окна, а из окна дуло. Штирли
1. Не изменяется количество оперативы
2. Не меняется число регистров в устройствах
3. Подключенные устройства не отлетают по первой прихоти
4. Набор машинных команд не меняется. *Этот принцип отлично отлетает когда мы добираемся до микропрограммирования)*
4. Набор машинных команд не меняется. *Этот принцип отлично отлетает когда мы добираемся до микропрограммирования)*
[^bootle-neck]: Бутылочное горлышко - устойчивое выражение, означающее место в которое упирается вся пропускная способность системы. В данном случае все данные, команды, адреса и прочая жизненно необходимая для работы процессора информация идет через одну шину данных, и в эту шину очень сильно упирается производительность системы

View File

@ -0,0 +1,81 @@
---
tags:
- служебное/устарело
pun: Дай человеку рыбу и он будет сыт один день. Назови человека Сыт и он будет Сыт всегда
---
*Подробно про все алгоритмы сжатия написано у меня в [[Глава 2. Виды данных, их кодирование, команды#Всякие там алгоритмы сжатия|конспекте]], здесь же я просто пробегусь по методичке*
## Сжатие без потерь
**Типы алгоритмов сжатия без потерь:**
1. Поточные и словарные алгоритмы - сжатие на основе ранее встречавшихся последовательностей
2. Алгоритмы статистического (энтропийного сжатия) - используется информация о "частоте встречания" каких-то символов и использование наиболее коротких кодов для символов, которые встречаются чаще всего
### RLE
Групповое кодированиеRLE - *(run-length encoding)* - Серия повторяющихся величин заменяется двумя: значением и количеством. Цепочка из n одинаковых байтов (при байт/пиксел) будет заменена двумя байтами
### Кодирование по Хаффману
Все прям по задачке из ЕГЭ - вот последовательность символов - закодируйте ее неравномерным кодом так, чтобы длина была минимальной и все можно было однозначно раскодировать
*Препод пишет следующее*
> Используются коды переменной длины, причем более короткие комбинации для более часто встречающихся величин. Для эффективного кодирования надо иметь статистику: как часто встречаются разные значения - поэтому кодирование "в два прохода". Степень сжатия также зависит от типа изображения - плохо работает для файлов, содержащих длинные последовательности одинаковых пикселов. Процессы кодирования и декодирования - сравнительно медленные процессы. Алгоритм очень чувствителен к "потере" битов в закодированных данных.
### LZW (Lempel-Ziv-Welch)
Это целое семейство алгоритмов, основой которых является идея о том, кодировать данные частями этих самых данных.
В процессе сжатия данных мы читаем файл и попутно собираем словарь, к которому обращаемся, когда находим совпадения
*Препод пишет:*
> Используется в архиваторах. Подобно алгоритму Хаффмана заменяет длинные последовательности более короткими, но не требует предварительно собирать статистику, он формирует все более эффективную 80 таблицу кодирования по мере продвижения по шифруемому массиву. Более "шумные" изображения кодируются хуже. Поэтому иногда рекомендуется подавить низкочастотной фильтрацией высокие пространственные частоты на изображении Типичные коэффициенты сжатия между 1:1 и 1:3, хотя иногда м.б. и 1:10. Этот алгоритм используется в графических форматах GIF и TIFF
## Сжатие с потерями
### JPEG
*Те еще танцы с бубном и самое длинное описание алгоритма в конспекте. Здесь я подробно приводить не буду и ограничусь методичкой*
Идейно базируется на биологии человеческого глаза - в нашем глазу в десятки раз больше рецепторов, отвечающих за восприятие яркости и зрение в темноте, чем рецепторов отвечающих за зветное зрение. Поэтому логично как будто бы кодировать в основном информацию о яркости, а информацию о цвете частично выкидывать и при этом наш глаз не заметит большой разницы
Вторая идея - на художественном изображении или фотографии 2 рядом стоящих пикселя как правило близки по цвету
Этапы следующие:
- Конвертнуть изображение из RGB в YCbCr, для того, чтобы компонента яркости $Y$ стала явной
- Сразу же избавиться от части информации о цвете (глаз все равно не заметит. а уже на этом этапе изображение уменьшается в 2 раза)
- Разбить изображение на блоки 8х8. Для каждого канала (Y, Cb, Cr) это делается отдельно. Для я яркости используется разбиение по 16x16 дискретные косинусные преобразования[^1]
- Значения, получившиеся после преобразования делят на опытным путем найденные числа[^2]. и округляют результат деления до целого. В матрице при этом возникает много нулей - что нам и нужно
- Получившиеся блоки с кучей нулей сжимают алгоритмом сжатия без потерь (отлично подходит RLE). При этом коэффициенты для деления в предыдущем шаге специально подобраны так, чтобы чем ближе к нижнему правому концу матрицы, тем больше нулей, поэтому кодируем под RLE мы не при помощи записи матрицы по строкам, а как бы зигзагом. В конце ставится специальный байт, означающий конец этого блока
- Чтобы еще сильнее сжать информацию, ее переводят в битное представление, после чего применяют алгоритм Хаффмана, чтобы оно занимало как можно меньше места в битах. При этом все таблицы для алгоритма Хаффмана составлены заранее, чтобы не тратить на них место
- Итоговый результат записывается в файл в виде блока. Потом процесс повторяется отдельно для каждого канала (Y, Cb, Cr) отдельно и выходные данные пишутся в файл вместе с другой служебной информацией, которая нужна будет для расшифровки данных
Это тут я еще упростил, но Препод написал и то меньше, так что этого должно хватить на приличный ответ.
[^1]: Дело в том, что было доказано, что все значения в таких матрицах представимы в виде комбинации заранее определенных 64 узоров с разными коэффициентами. Мы делаем это страшное преобразование для того, чтобы эти коэффициенты найти. Подробнее об этом написано в конспекте
[^2]: Каждой ячейке соответствует свое число. Их можно записать в виде матрицы, где каждой ячейке получившейся в результате дискретных косинусных преобразований матрицы, будет соответствовать (находящаяся на той же строке и в том же столбце) ячейка другой матрицы. Вторая матрица называется матрицей квантования
### MPEG
Фактически базируется на JPEG и разделяет с ним идеи. Помимо них добавляется еще одна:
- Между двумя отдельными кадрами видео изменения как правило малы
Краеугольным камнем всего формата являются кадры двух типов: I - кадры, сжатые полноценно и независимо, и P - кадры, которые построены с ссылкой на предыдущий (при этом учитывается как изменение пикселей, так и смещение отдельных блоков пикселей в пространстве)
Для еще большего сжатия появляются B-кадры, которые вообще говоря генерируются, а не строятся на основе исходного видеоряда. Получаются они некоторым подобием среднего арифметического двух соседних кадров категорий I и P
![[Глава 2. Виды данных, их кодирование, команды#^9aa8aa]]
Степень сжатия можно повысить следующими способами (не очень точный пересказ методички):
![[Глава 2. Виды данных, их кодирование, команды#Основные пути повышения степени сжатия]]
### Motion-JPEG
Видео представляет собой последовательность из изображений - кадров. Если закодируете каждый из этих кадров алгоритмом JPEG независимо, то получите Motion-JPEG (M-JPEG). Он применяется при монтаже видео и позволяет реализовывать прикольную прокруту по кадрам, так как обеспечивает одну из самых больших скоростей доступа к произвольному кадру
Работает он быстро так как в наше время во многих процессорах есть аппаратное ускорение различных операций над JPEG

View File

@ -0,0 +1,41 @@
---
tags:
- служебное/в_процессе
pun: "Как называют человека, который пожертвовал кусочек печени? \rОбеспеченный!"
---
# Схема процессора
![[Pasted image 20241112190401.png]]
*Схема процессора. Ее вероятно придется заучить*
*Далее мы будем ее подробно жевать, вся эта картинка станет вам понятна*
# Выполнение команд процессором
*Вот честно, вообще не понял, что тут препод спрашивает, потому что этому уделен либо один абзац, либо весь билет, либо вся методичка до начала работы с памятью. Думаю для ответа на билет хватит этого абзаца из методички* #служебное/пересмотреть
"Выполнение команды может быть сведено к нескольким (одновременно, либо последовательно в времени) операциям пересылки из регистра в регистр возможно с промежуточным преобразованием пересылаемых двоичных слов на комбинационных логических схемах"
> [!info]- Если все же хотите послушать отсебятину билетёра
> Процессор читает команду из памяти и передает ее на дешифратор, который уже разбирается, как следует ее доставить в устройство управления. Устройство управления понимает, что команда вроде `mov rax, [rbp - 4 * rcx + 12222]` - чет слишком сложно, чтобы сделать за раз и формирует последовательность микрокоманд, которые в итоге приводят к тому, что написанная пользователем команда будет исполнена, подавая управляющие сигналы на стробы пересылки между регистрами, АЛУ и прочая
# Операционные устройства
Современный процессор далеко не монолитен и, как правило, состоит из нескольких операционных устройств. [[Глава 3. Процессор#^68eab4|Можно обойтись и без них]], но тогда процессор превратится в черепашку.
Само по себе операционное устройство - аля сопроцессор, выполняющий строго определенный круг задач. Например сопроцессор с плавающей точкой встречался нам в 7 методичке. Преподаватель приводит следующие операционные устройства:
![[Глава 3. Процессор#^operating-units-list]] ^54a14c
Могут быть и другие, в зависимости от назначения процессора. Например сейчас часто алгоритмы декодирования изображений реализованы аппаратно.
![[Глава 3. Процессор#Структура операционного устройства]]
# Операционные устройства с магистральной структурой
![[Глава 3. Процессор#Операционные устройства с магистральной структурой]]
# Устройство управления
^a29a65
![[Глава 3. Процессор#Устройство управления]] ^522375

View File

@ -0,0 +1,92 @@
---
tags:
- служебное/доработать
pun: Пуля, попавшая в школьного учителя, вышла и зашла как положено
---
## Устройство управления
Если вы не помните про то, как микропрограммный автомат связан с устройством управления, перечитайте прошлый билет, а точнее его [[03 - Схема процессора (схема). Выполнение команд процессором. Операционные устройства. Типы операционных устройств с магистральной структурой. Устройство управления#^a29a65|последний абзац]]
## Микропрограммирование команд
Есть 2 основных вида микропрограммных автоматов, по названиям которых дается название всему УУ.
![[Глава 3. Процессор#^CU-types-list]]
Первый один раз и на века спаивается производителем (подробнее можно почитать [[Глава 3. Процессор#^846e1e|тут]]), его, как понимаете, не покодишь, а вот второй вполне можно.
*Я кратко резюмирую написанное [[Глава 3. Процессор#Микропрограммный автомат с программируемой логикой|тут]]*
Микрокоманды разбивают большую команду (`add rax, [rbx + 4 * rcx - 40]`) на маленькие шаги, чтобы не приходилось вообще все опкоды реализовывать аппаратно, это позволяло в свое время не слабо экономить на аппаратных частях процессора. Реализация примерно такая:
![[Глава 3. Процессор#^struct-image]]
![[Глава 3. Процессор#^f2908e]]
## Структура процессора с 3 шинами
*будет еще раз затронута при микропрограммировании, но раз препод расставил вопросы в таком порядке, приведу ее и тут*
![[Глава 3. Процессор#^b0a065]]
Запоминать эту радость надо, видимо, наизусть, но попытаюсь облегчить это дело, сдобрив пониманием:
> [!comment]- Примечение билетёра о том, почему модель такая, какая она есть
> **Можете не читать это, а просто заучить, я не заставляю**
>
> В общем-то здесь просто минимальная модель процессора, какая вообще возможна (и с оговорками). Меньше ее сделать нельзя по двум причинам:
>
> - На ней будет показываться микропрограммирование, что закрепляет часть элементов
> - Без остальных частей не заведется ни один уважающий себя процессор
>
> Сначала рассмотрим "обрубок АЛУ" как я его называю. Ранее по билетам%%укажи где%% я упоминал, что минимальный процессор должен уметь в операции сложения, сдвига и инверсии. Ну короче вот они все тут и стоят
>
> Любой процессор должен иметь счетчик команд для того, чтобы хотя бы просто идти вперед по списку команд.
>
> Регистр адреса нужен банально как дополнение к счетчику команд, чтобы формировать адреса операндов, без него совсем тяжко
>
> 2 регистра нужны, потому что архитектура у нас регистровая, а не стековая или еще какая, поэтому все операции через регистры, а значит регистров как минимум больше одного. Больше двух для целей демонстрации тоже смысла делать не было, вот препод и не нарисовал
>
> Буферный регистр придется запомнить, потому что он нужен во операциях сдвига или подобном, чтобы предотвращать гонки (race condition), когда результат операции может меняться из-за того, что в одном месте ток пришел на 3 наносекунды позже
>
> Константная единица нужна, чтобы можно было при демонстрации прибавить кол к какому-нибудь числу. Теоретически она выплевывает что-то типа $00 \dots 001$
>
> Память оставлю без комментариев - мы никуда без оперативы
Касаемо назначения циферок и как это дело микропрограммировать будем рассматривать [[#Пример микропрограммы|дальше]]
## Микрокоманды и микропрограмма
![[Глава 3. Процессор#Микрокоманды и микропрограммы]]
## Пример микропрограммы
*Тут обращаемся к нашей схеме*
![[Глава 3. Процессор#^b0a065]]
И вставлю сюда же чуть более обстоятельные объяснения:
![[Глава 3. Процессор#Процессор с тремя внутренними шинами]]
*Теперь я постараюсь объяснить, зачем тут каждый из шагов*
Во-первых оставлю отрывок из методички о том, как это объясняет препод:
![[Pasted image 20250106002341.png]]
%%*Того, что было написано в методичке маловато для того, чтобы закодить этот алгоритм, поэтому придется реализовать его вам самостоятельно. Ну или пишите - попробую реализовать его, но сейчас как будто бы билетов еще много впереди*%%
Теперь что касается строк таблицы (вместо "Регистр 1" и "Регистр 2" буду писать R1, R2):
1. Подать R1 на BB, подать R2 на AB, выполнить суммирование
2. Сумму поместить в регистр R1
3. Снова сложить R1 и R2 (повторяет шаг 1)
4. Поместить результат сложения в R2
5. Подать на BB вместо содержимого регистра кучу единиц, а на AB положить R1, инвертировать оба значения и результат сложить
6. Результат сложения в R1
Тут по идее 3 разных программы:
1. R1 = R1 + R2
2. R2 = R1 + R2
3. R1 = not R1

View File

@ -0,0 +1,47 @@
---
tags:
- служебное/в_процессе
pun: Я отказался от хлеба, и теперь все мои проблемы... Крошечные!
author: mrqiz
revised:
---
# Кэш-память
> **Кэш-память** - промежуточный буфер, предназначенный для хранения информации, которая будет запрошена с наибольшей вероятностью.
## Основные принципы организации кэша
- **Принцип временной локальности** - имеется высокая вероятность многократного обращения к конкретным данным в памяти в рамках короткого промежутка времени.
- **Принцип пространственной локальности** - имеется высокая вероятность обращения к нескольким рядом стоящим ячейкам памяти.
## Виды кэш-памяти и их принцип работы
### Полностью ассоциативная кэш-память (ПАКП)
Чтобы процессор мог прочитать данные из памяти - ему необходимо указать адрес из нескольких битов, в котором лежат эти данные. Для идентификации данных в ПАКП требуется взять 20 старших битов адреса.
У каждой ячейки памяти есть свой "тег" - часть адреса, которая говорит о том, какие данные лежат в строке. При запросе данных из памяти происходит сравнение 20 старших битов данных с тегами всех строк в кеше.
Собственно, есть понятия кэш-попадания и кэш-промаха. Первое говорит о том, что тег из адреса имеет совпадение с каким-то тегом из кэша, соответственно есть возможность получить данные из кэша (что будет быстрее, чем идти за ними в основную память). Кэш-промах же говорит о том, что таких данных в кэше нет и придется обратиться в память.
Минус ПАКП - необходимость использования большого количества тразнзисторов для сравнения адреса с тегами всех строк кэша.
### Ассоциативная по множеству кэш-память (АпМКП)
В АпМКП адрес делится на тег, индекс и смещение. Индекс указывает, на какой кэш-строке находятся данные. А смещение определяет, какой именно байт или элемент данных нужно извлечь из строки кэша.
> [!comment]- От билетера: схема АпМКП
> ![[Screenshot 2025-01-08 at 1.24.35 PM.png]]
### Кэш-память с прямым отображением
Также как и в АпМКП - адрес в памяти делится на тег, индекс и смещение.
Индекс указывает на конкретную строку кэша, где могут находиться данные. Процессор использует индекс, чтобы обратиться к определенной строке кэша и извлечь данные из нее. Затем из этой строки берется тег, который соответствует старшим разрядам адреса, и происходит сравнение с тегом входного адреса.
Если тег из адреса совпадает с тегом в строке кэша - мои поздравления, у вас кэш-попадание.
Недостаток прямого отображения - каждый блок данных может храниться только в одной определенной строке кэша, что увеличивает вероятность кэш-промахов, особенно если несколько блоков данных имеют одинаковый индекс.
> [!comment]- От билетера: схема прямого отображения
> ![[Screenshot 2025-01-08 at 1.23.40 PM.png]]

View File

@ -0,0 +1,192 @@
---
tags:
- конспект
- служебное/в_процессе
source:
- источник не указан
---
*Уточняю, что конспект - естественный выхлоп моей работы пока я ищу информацию по билету. О полноте речи не идет и приложен он тут только потому что я иногда на эти конспекты ссылаюсь и потому что мне не жалко*
## 2.5. Графические данные, их представление и кодирование
### Классы изображений
### Кодирование цвета
### Способы и точность кодирования цвета для отображения
### Форматы для хранения графических данных
### Краткая характеристика наиболее распространенных растровых форматов
## Всякие там алгоритмы сжатия
### Алгоритмы сжатия без потерь
Неплохое видео: https://www.youtube.com/watch?v=CJFUN6BrkGE
*Априори все считается последовательностью чисел. Как правило за единицу данных, которые будут сжиматься, берется 1 байт*
#### Групповое кодирование RLE
![[Pasted image 20241106185944.png]]
Вместо того, чтобы писать последовательно много раз одинаковое значение, записывается сначала количество повторений байта, а затем сам байт
То есть если у нас есть последовательность 111112222222227, то мы как бы говорим: "запиши **5** раз **1**, потом **9** раз **2**, потом **1** раз **7**". То есть запишется оно как: "[5]1[9]2[1]7" и если исходное сообщение занимало у нас 15 байт, то новое 6 байт.
Основная проблема данного алгоритма в том, что число повторений тоже надо хранить и остается хранить их только в сжатом тексте, так что если повторяющихся данных не так много, то алгоритм становится даже вреден. Например: 112431 превратится в [2]1[1]2[1]4[1]3[1]1, и того 10 байт против исходных 6. То есть размер даже увеличился
То есть алгоритм отлично себя показывает на изображениях, где много областей сплошной одноцветной заливки (как например схема самого алгоритм, приведенная выше)
### Кодирование по Хаффману (Huffman, 1952)
Много поработав с естественным языком, мы довольно быстро заметим, что определенные буквы в нем встречаются чаще чем другие. Частотностью символа называется количество этого символа в тексте, к количеству символов в тексте. Проще говоря какой процент всех символов составляет например буква "а"
Эта особенность языка испокон веков использовалась для взлома простого шифра подстановки [^substitution-cipher], а потому частотность символов была многократно посчитана для почти всех языков, которые имеют письменность. Вот например частотность символов русского языка:
![[Pasted image 20241106193807.png]]
Видно, что буква "о" упоминается существенно чаще, чем буквы вроде "ф" или многострадальной "ё", (к которой у русских большая нелюбовь из-за неудобства ее печатного набора).
Эта особенность, которая несколько веков портила жизнь людям и не давала зашифровать сообщение, но ее можно обернуть и себе на пользу: при шифровании текста логично использовать для шифрования буквы "о" символ с наименьшей длинной, чуть длиннее сделать "е", еще чуть длиннее "а" и так далее вплоть до "ё", которую зашифруем уже как получится.
Ну и вот перед нами знакомая задачка из ЕГЭ - подобрать коды для символов так, чтобы их можно было однозначно декодировать, а длина сообщения была наименьшей. Здесь же предлагаю вспомнить, что такое прямое условие Фано - ни одно кодовое слово не может быть началом другого кодового слова. Это является условием, чтобы наши сжатые данные можно было однозначно декодировать
После этого мы алгоритмически реализуем подбор таких символов.
**У этого метода есть одна проблема технического характера**: частотности символов для языка в целом и для конкретного файла в частности могут весьма сильно различаться, а мы ведь этот алгоритм не только к текстам хотим применять (У нас-то в голове все с байтами работает). Построить таблицу частотностей для конкретного файла - пол беды, это займет O(n), что вполне допустима даже для гигабайтных данных. А вот как ее при разжимании получить? В классической реализации алгоритма Хаффмана она хранится в начале файла, но она, как вы можете догадаться, сама прибавляет размера нашим данным.
**У этой проблемы есть решение** - на практике мы можем не генерировать таблицу частотностей, а производить кодирование и построение дерева кодирования символов параллельно. Алгоритм Молодяковым не описан, просто знайте что он есть. Если кому интересно, он разбирался в этом [видео](https://youtu.be/CJFUN6BrkGE?si=AX_-n_2Hn1NQAD0k&t=571) (или если ютуб не грузит: https://vk.com/video-209186427_456239058 на 9:41). Этот алгоритм называется "адаптивный метод Хаффмана"
[^substitution-cipher]: Шифр простой подстановки - шифр, где каждому символу исходного алфавита (например русского), ставится в соответствии символ другого алфавита. Классический пример - замена одних букв на другие: а -> в, г -> а и т.д. И тогда сообщение "Бегите, глупцы" станет "Гжакфж, анхсшэ" (тут поменяны и другие буквы, можете попытаться прикинуть, какой алфавит тут использовался). Символом другого алфавита может быть и просто другой символ. Ярким примером может стать например шифр Стенфорда Пайнса из Гравити Фолз (кстати рекомендую попробовать его расшифровать, мне это доставило некоторое удовольствие)
### Алгоритм LZW (Lempel-Ziv-Welch - 1984)
*Весьма сложный для понимания на слух. Алгоритм существует в двух вариантах LZW и LZW78*
**Идея**: до этого мы кодировали текст уменьшая длинну символов, теперь мы кодируем текст при помощи частей этого самого текста. То есть в слове **abra**cad**abra** есть 2 абсолютно идентичных набора символов. Хотелось бы это как-то учитывать при кодировании
*Держим в уме, что текст тут только для примера и действительности мы всегда работаем с последовательностями байт*
#### LZW исходный
> [!note]+ Скользящее окно
> Некий кусок непрерывной памяти из двух частей - словаря, и буффера. Изначально кодируемый текст, насколько помещается, заносится в буффер (представьте буффер справа), а в процессе кодирования вся эта область памяти сдвигается влево (обычным сдвигом << 8)
**Идея**: кодируемый текст мы помещаем в буффер и в процессе обработки смещаем его в словарь, а внутри словаря потом в процессе кодирования ищем совпадения. Если совпадение нашлось, мы просто указываем в словаре где это совпадение можно отыскать
**Реализация (в общих чертах)**: загоняем весь текст в буффер, после чего начинаем искать сопадение для первого символа в словаре (в самом начале кодирования совпадений не будет). Пока совпадений нет, сдвигаем всю цепочку на 1 влево, если есть еще символы, которых нет в буффере, попутно доставляем их туда *(сдвинулись на 1 влево, в буффере освободилось место под один символ, дописываем в это место следующий в файле символ)*. Словарь и буффер - одна область памяти, называемая скользящим окном (см примечание выше), поэтому при сдвиге влево на один символ, самый левый символ из буффера появится в словаре, вытеснив самый старый символ уже словаря. Вытесненный символ нигде не хранится и просто исчезает из оперативной памяти. Как только есть совпадение на 1 символ, пытаемся найти совпадения на 2 символа, потом на 3 и так далее. То есть пытаемся найти как можно более длинное совпадение с содержимым словаря. Отмечу, что совпадения мы ищем даже тогда, когда словарь пуст. Если такое есть - даем на него ссылку в закодированном сообщении словаре (в классической реализации - смещение от конца влево и длину совпавшего куска)
**Проблема:** Если сначала мы ищем совпадение в один символ, потом в 2 символа, потом в 3 и так далее, то оценка сложности покажет сложность алгоритма по времени $O(n!)$. Не очень хорошо. Чем больше будет размер скользящего окна, тем больше потенциальных длинных цепочек мы сможем найти и тем сильнее, соответственно, сжать данные, но тем дольше будет процесс кодирования
#### LZW78
*Модифицированная версия, также и проще для понимания*
У нас есть кодируемый текст и словарь. Поскольку примером данных будет текст, словарь у нас будет представлять обычный массив строк (только придется договориться, что нумерация в нем начинается с единицы а не с нуля).
**Идея**: мы кодируем текст и попутно составляем словарь. Мы ищем повторяющиеся последовательности символов длиной начиная от нуля и доскольки угодно. Если некоторой последовательности еще нет в словаре, мы ее туда заносим, если есть, мы в выходных данных даем номер совпавшей последовательности
> [!note]+ Примечание
> Искать последовательности мы начинаем с длины 1, что означает, что при кодировании в словарь сначала добавится вхождение в 1 символ. Потом если с этим вхождением в 1 символ случится совпадение, в словарь будет добавлено совпадение уже из двух символов, а если будет совпадение с последовательностью из двух символов, будет добавлена новая последовательность из 3 символов.
>
> Каждая новая добавленная последовательность создается из совпавшей последовательности + одна буква справа от нее. То есть если "abba" уже есть в словаре, а совпадение случилось в состоянии буфера "**abba**helloworld", то следующей в словарь добавится последовательность "abbah", потому что слева стояла буква "h"
**Реализация**: теперь вместо символа или последовательности символов мы пишем номер, под которым соответствующая последовательность хранится в словаре (напоминаю, что нумеруем элементы массива в этом примере мы с **единицы**), после чего добавляем следующий за этой последовательностью символ. Если символ в словаре не найден, пишем в качестве числа 0. `{'a', 'b', 'r'}`)*, а вот потом встретится "a", которая есть в словаре, поэтому мы напишем ее порядковый номер, а затем следующий за совпавшей последовательностью символ: 1c (словарь: {'a', 'b', 'r', 'ac'})*, потом в ход пойдет "ad", который закодируется соответственно в 1d и так далее после кодирования получим следующий результат: 0a0b0r1c1d1b3a *(словарь: {'a', 'b', 'r', 'ac', 'ad', 'ab', 'ra'})* (заметим, что в данном случае мы ничего не сжали. Это нормально, потому что данные коротковаты, а алгоритмы сжатия дописывают довольно много информации. Порой сжатие не эффективно, тут ничего не поделать)
**Проблемы**: пусть здесь мы и поправили скорость сжатия (теперь на поиск совпадений уходит $O(n)$), а также мы убрали ограничения на размер скользящего окна и теоретически можем искать совпадения большой длины, можно увидеть, что в этом варианте алгоритма мы не заметили, что "abra" встречается 2 раза без изменений. То есть чтобы алгоритм был эффективен, желательно данные иметь побольше. Также не трудно понять, что если длинных цепочек повторяющихся данных у нас нет, то сжатие пойдет во вред размеру файла и это надо учитывать, поэтому если в файле нечему повторяться, то этот алгоритм не только не эффективен, но подчас и вреден, как мы могли убедиться
### Алгоритмы сжатия с потерями
*Когда мы говорим о сжатии какого-нибудь текстового документа, потери данных оче ид о н прив дут ни к ч му хор шему, как можете видеть, читать такое не то чтобы очень приятно. Но вот если дело касается изображений - другой разговор. Наш глаз, вообще говоря, штука крайне не точная и вполне может не заметить каких-то деталей. Так что для фото и видео сжатия с потерями - отличный выход (потому что весят эти картиночки они будь здоров)*
### JPEG
JPEG - формат хранения изображения с потерями. Само по себе его обоснование довольно сложно и требует некоторых знаний в области математики. Тем не менее основывается он на некоторых вполне понятных идеях:
1. Если мы сжимаем фотографию или художественное полотно, то как правило 2 соседних пикселя будут близки по цвету
2. Человеческий глаз построен таким образом, что он гораздо восприимчивее к перепадам яркости, чем к изменению цвета (кому интересно, это связано с тем, что в [нашей сетчатке глаза](https://ru.wikipedia.org/wiki/Сетчатка) больше [палочек чем колбочек](https://ru.wikipedia.org/wiki/Фоторецептор)). То есть человеческий глаз намного чувствительнее к изменению яркости нежели к изменению цвета
Процесс сжатия в этом формате довольно длинный. Подробно все шаги пояснять не буду, потому что это ну прям совсем хана
1. Для того, чтобы применить знание о том, что наш глаз лучше воспринимает перепады яркости, чем цвета, нам нужно как-то отделить цвета от яркости. Эта задача была решена еще во времена появления цветных телевизоров. Так как переход с ч/б на цветные был постепенный, надо было научиться как-то транслировать изображение, чтобы его могли читать и те и другие модели.
Тогда же были получены формулы перевода из RGB в другой формат - цветоразностное кодирование^[Далее в эфир 3 полученных числа кодировались по 3 раздельным каналам. ЧБ телевизоры воспринимали только один - $Y$, а цветные - все 3 канала] (яркость, коэф синего, коэф красного). $Y$ - яркость: $Y = 0.299R + 0587G + 0.144B$. $Cb$ - коэффициент синего: $Cb= 0.1687R -0.3313G +0.500B$. И $Cr$ - коэффициент красного: $Cr= 0.500R -0.4187G +0.0813B$.
Теперь именно при помощи этих чисел мы будем записывать все пиксели исходного изображения
2. На втором шаге мы уже сделаем сжатие - отбросим часть цветовых данных, но сохраним яркость. Глаз не очень чувствителен к такому изменению
Для этого изменим немного кодирование данных: возьмем квадрат 2х2 пикселя и будем считать, что он весь закрашен одним цветом, но при этом сохраним все значения яркостей. То есть вместо кодирования всех трех компонент для каждого отдельного пикселя, для каждого пикселя мы кодируем только яркость, а цвет кодируем для всего квадрата сразу. Таким образом из 12 значений (по 3 компоненты на каждый пиксель) мы получаем всего 6 (4 значения на яркости отдельных пикселей и 2 значения на цвет квадрата). Уже на этом этапе мы уменьшили размер изображения в 2 раза, а качество для нашего глаза еще не пострадало
3. Следующий шаг самый сложный как для реализации, так и для понимания. Упирается он в следующее размышление - у нас может быть разная детализация изображения. В какой-то области находится много мелких деталей, а в какой-то меньше. Это очень легко увидеть на картинах художников. Наша задача определить места, где мало деталей и закодировать их меньшим количеством информации. *Наша задача понять, что же с технической точки зрения означает "количество деталей"*
Размышления над этим привели к страшной математике: [дискретному косинусному преобразованию](https://ru.wikipedia.org/wiki/Дискретноеосинусное_преобразование). *Про его устройство Молодяков не пишет и надеюсь не спрашивает*.
Изображение разбивается на блоки 8х8^[Сейчас размеры блока яркости удваиваются и яркость кодируется блоками по 16 на 16]. Внутри этих блоков мы берем отдельно 3 компоненты (те самые яркость и 2 цвета) и отдельно над каждой проводим одни и те же манипуляции: берем их значения и из интервала 0-255 переводим в -128 -127. Было доказано, что любые значения в получившейся матрице можно получить сложением 64-х отдельных элементарных (и не очень) матриц. Все они получены были косинусным преобразованием и выглядят так:
![[Pasted image 20241109173751.png]]
Дальше идет не очень понятный мне этап преобразования исходной матрицы 8 на 8 к матрице по примерно следующей формуле:
$$
G_{ij} = \frac{1}{4} C_{i}C_{j}\sum_{x=0}^{7} \sum_{x=1}^{7} p_{xy}\cos\left( \frac{(2y+1)j\pi}{16} \right)\cos\left( \frac{(2x+1)i\pi}{16} \right)
$$
Тут боюсь я и сам не в курсе, откуда она взялась.
В общем на выходе получается примерно следующая матрица
![[Pasted image 20241109180727.png]]
Для нас самое важное сейчас то, что чем ближе к правому нижнему углу, тем числа ниже. При этом эта матрица кодирует "значимость элементов для нашего глаза"^[Не спрашивайте как до этого додумались. Разработка формата по некоторым источникам велась 6 лет. Я не смогу ужать 6 лет страданий ученых в 3 абзаца] %%Может быть дополню когда-нибудь маленькой заметкой откуда взялось уравнение и в чем его основная идея. По крайней мере полезно будет для моего ящика для заметок%%.
4. Далее из-за пазухи достаем уже заранее за нас составленную матрицу квантования и делим попарно элементы матрицы после преобразования на матрицу квантования^[Замечу, что для яркости одна матрица кватнования, а для цвета другая. Все матрицы квантования подбирались опытным путем (и существенное время). Отрегулировать степень сжатия можно умножением этих матриц на константу] и округляем значения
![[Pasted image 20241109181231.png]]
После этого процесса получилось очень много ноликов - этого мы и добивались - выжили только существенные детали, а остальные съело делением. Вот эту-то матрицу мы и будем хранить.
Для того, чтобы компактнее сохранить эту матрицу, но не выбросить все числа из нее, мы снова будем сжимать ее без потерь. Собственно для этого мы и добивались, чтобы было как можно больше нулей. Нам нужно сохранить матрицу так, чтобы как можно большее количество нулей шло подряд. Как я уже говорил, наиболее трудноразличимые детали располагаются в нижнем правом углу, то есть вероятность того, что в ячейке матрицы не ноль уменьшается по мере продвижения по диагонали вправо вниз
Поэтому решили записывать числа зигзагом по этому направлению:
![[Pasted image 20241109181855.png]]
5. После того, как мы писали этот ужас мы сжимаем его страшной помесью Хаффмана и RLE. Описывать я это дело пожалуй не буду, просто скажу, что таблицы для алгоритма Хаффмана построены заранее.
В целом этот алгоритм позволяет сжимать изображения в десятки раз. (вплоть до 50-кратного уменьшения размера)
Повторим еще раз идейно наши шаги:
```mermaid
graph TD;
convert(Перекодировать цвета, чтобы появился явный параметр яркости)-->resize(Выкинуть часть информации о цвете, которую глаз не заметит);
resize-->split(разбить изображения по каналам, а содержимое каналов поделить на группы по 8х8 для цветов и по 16х16 для яркости);
split-->DCT(Выявить какие узоры из числа заранее известных 64-х в каких пропорциях присутствуют в группах);
DCT-->clean(выкинуть все несущественные узоры);
clean-->compress(Оставшиеся коэффициенты матрицы компактно упаковать);
compress-->Готово!;
```
### MPEG
*Сжимаем видео*
Фактически базируется на JPEG и разделяет с ним идеи. Помимо них добавляется еще одна: ^fe65ee
- Между двумя отдельными кадрами видео изменения как правило малы
Краеугольным камнем всего формата являются кадры двух типов: I - кадры, сжатые полноценно и независимо, и P - кадры, которые построены с ссылкой на предыдущий)
В целом уже довольно сильное сжатие можно было бы достичь и этим, но мы пошли чуть дальше и ввели категорию B - кадры, которые ссылаются на следующий и предыдущий кадры. В реализациях классического MPEG алгоритма они вообще просто генерируются на основании двух ближайших кадров категорий I и P. Обычно являются неким "средним арифметическим" между этими двумя кадрами. на эту категорию ничего не ссылается
Примерное кодирование выглядит так: нeзависимо кодируется кадр видео целиком. Обычно кодируются каждый пол секунды видео. Затем если мы говорим про частоту кадров в 24 кадра/секунду, то на равных промежутках вставляется еще 3 кадра категории P. Они кодируются, как и было сказано, со ссылкой на предыдущий кадр. А дальше добивается это дело B-кадрами. Судя по описанию методички их по факту даже нет в исходном видеоряде. Они просто строятся на основе двух соседних кадров^[Чем-то напоминает dlss если вы понимаете о чем я]. Обычно кодирование ведется группами по N кадров. Такие группы могут декодироваться независимо от других групп. Обычно размеры группы естественным образом определяются расстоянием между кадрами типа I. ^9aa8aa
Говоря о самих изображениях, они состоят из макроблоков (размером 16х16 пикселей %%ничего не напоминает?)%%). Такие блоки имеют привычку смещаться и немного изменяться со временем. Вот их смещения обычно отслеживают и сжимают. Сжатие происходит очень сходно с JPEG
#### Основные пути повышения степени сжатия
- Улучшение сжатия I-кадров
- Улучшение подбора векторов смещения блоков (исходно - среднеквадратичное смещение%%Я тоже не в курсе, что за смещения векоторов. Такое чувство, что Молодяков тут не объясняет а напоминает%%)
- Если у вас еще остались тяжелые наркотики можете посравнивать коэффициентики в соседних блоках 8х8. Там адовы преобразования можно усреднить значения соседних блоков и добавить степени сжатия
- Если сжать кадры слишком сильно, то будут видны края блоков, но в целом можно алгоритмами убирать их на пост обработке и продолжать увеличивать сжатие
- Можно предварительно обработать видео, чтобы оно лучше подходило для сжатия (вырезать многие детали, которые все равно не заметны), вырезать разные шумы и "высокие частоты"^[Молодяков их так назвал. Что это в контексте изображения - ума не приложу]
### Motion-JPEG
Если видео короткое, или вам в целом все равно, что один видосик будет занимать у вас пол диска, то можно обойтись и Motion-JPEG (M-JPEG). Он заключается в основном в том, что все кадры будут независимо сжаты при помощи JPEG.
Это помогает при монтаже видео и в целом JPEG обладает аппаратным ускорением^[То есть в процессоры вмонтированы устройства подобные тем, что мы на схемаче собираем, которые гоняют только операции над JPEG и ничем другим не занимаются. За счет того, что такие сопроцессоры не программируются а один раз собраны, скорость обработки получается очень быстрой]

View File

@ -0,0 +1,275 @@
# 3.1 Процессор - аппаратный уровень. Операционные устройства
### Какие бывают операционные устройства
Современный процессор уже не является монолитным устройством, он уже давно разбит на несколько частей и сопроцессоров. В методичке все это именуется операционными устройствами. Там же приводятся следующие операционные устройства:
- целочисленной арифметики
- логических операций
- десятичной арифметики
- чисел с плавающей запятой
- векторных операций
^operating-units-list
*В зависимости от назначения процессора могут так же быть операционные устройства: правления потреблением,
графических операций, упаковки/распаковки изображений и др.*
> [!note]- Примечание билетёра
> Есть подозрение, что операционными устройствами преподаватель называет любые аппаратные ускорители, которые производитель зашивает **на кристалл**
Весь этот зоопарк сопроцессоров вообще говоря не обязателен. В минимальном процессоре может быть только модуль целочисленной арифметики, арифметико-логическое устройство которого должно уметь выполнять только: ^68eab4
- логические операции (побитовые И, ИЛИ, НЕ ИЛИ и т.д.)
- сдвиги
- инвертирования
- сложение чисел в формате с фиксированной запятой. Все остальное вообще говоря можно собрать на базе этого
*Однако такой вариант работает **невероятно медленно***. Сейчас обычно пытаются все ускорить аппаратно (то, что мы делаем на "схемаче")
### Структура операционного устройства
^2ec856
Каждое операционное устройство должно иметь:
- Собственные регистры для хранения данных
- Сами схемы, которые выполняют какие-то действия над данными
- Входы и выходы, чтобы общаться с процессором и прочим. *Умные дяди называют это шинами*
^op-struct
**Регистры** - ячейки для хранения данных, которыми операционное устройство пользуется при преобразованиях. Хранят данные. *(На схемаче мы такие собирали на основе триггеров, если помните)*
Регистры бывают:
- **Программно-видимые явно** (rax, rbx, rcx, ST(0), ST(1) и т.д.)
- **Видимые косвенно** ("теневые регистры дескрипторов сегментов". В 64 битном процессоре мы их особо не видим, а в MS-DOS насмотрелись)
- **Внутренние для специальных целей** ("для них по крайней мере известно, для чего они" - цитата из методички)
- **Внутренние для хранения промежуточных результатов**
- **Псевдо-регистры** - нужны для хранения констант вроде 0, 1, -1. В Intel например при микропрограммировании (о нем дальше по билету) вроде хранит константный 0
**Шины** - группы проводов c соединением *"рот в рот"*. Позволяют передать параллельно какие-то данные. Визуально выглядит как-то так:
![[Pasted image 20250101220837.png]]
%%Довольно прямолинейно)%%
**Вентили** - единичные логические элементы вроде НЕ И, ИЛИ, НЕ, И и прочие. В методичке изображаются так:
![[Pasted image 20250101221014.png]]
**АЛУ** - сердце процессора. Внутри себя не содержит памяти. Обычно принимает на вход содержимое одного или нескольких регистров и код операции, которую надо провести над полученными данными. Выполняет операцию и выплевывает результат на свои выходы %%Когда я собирал АЛУ, я там же еще и решал, на какие именно регистры я отдам результат, а также буду ли я обращаться к памяти при передаче данных в АЛУ%%
#### Конструкция АЛУ
Обычно в процессоре приветствуется "модульность" - полноценное АЛУ **собирается из АЛУ для одно разрядных операций** (например +, -, &, |, ~), а также имеет дополнительные входы и выходы, чтобы получать информацию от других таких же АЛУ (например о наличии переноса в предыдущих разрядах при сложении) и отдавать эту самую дополнительную информацию. В методичке приводится пример такого одноразрядного АЛУ
![[Pasted image 20250101221638.png]]
> [!tip]- Пояснение порядка работы схемы из методички
> "В левом нижнем углу схемы находится двухразрядный декодер, который порождает сигналы включения для четырех операций. Выбор операции определяется сигналами управления F0 и F1. В зависимости от значений Fo и F1 выбирается одна из четырех линий разрешения, и тогда выходной сигнал выбранной функции проходит через последний вентиль ИЛИ.
>
> В нижнем правом углу находится полный сумматор для подсчета суммы А и В и для осуществления переносов. Переносы необходимы, поскольку несколько таких схем могут быть соединены для выполнения операций над целыми словами. Одноразрядные схемы, подобные той, которая изображена на рис. 3.4, называются разрядными микропроцессорными секциями. Они позволяют разработчику сконструировать АЛУ любой желаемой ширины."
### Примеры выполнения элементарных действий
**Пересылка** - выходы одного регистра соединили с входами другого через вентиль побитового И
![[Pasted image 20250101222536.png]]
Для выполнения операции хватит и одного строба T1
Сдвиг (`rol`): 0-ой выход регистра R1 загоняется в 1-ый вход регистра R1, 1-й выход R1 в 2-й выход R1 ну и так далее. В 0-й вход R1 загоняется 0
![[Pasted image 20250101222755.png]]
регистр, как можно видеть по схеме, в итоге передает значение сам в себя, поэтому для исключения гонок (race condition)[^race_condition], операция происходит в 2 такта - сначала пишем во внутренний регистр, а потом из него выполняем сдвиг
[^race_condition]: В данном случае проблема в том, что содержимое 0-го бита регистра должно быть передано в 1-й бит регистра, а значение первого во 2-й и т.д. Но если по какой-то причине значение 0-го бита придет в 1-й раньше, чем тот успеет переслаться, то во 2-м бите окажется неправильное значение. Поэтому это и называется гонками - операция отрабатывает правильно, только если в "гонке" все участники "приходят" в нужном порядке. Это нехорошо и такое стараются устранять
**Сложение** - На схемаче мы уже одноразрядный сумматор собирали, надеюсь пояснений тут касаемо его идеи не требуется
![[Pasted image 20250101223535.png]]
Теперь касаемо особенностей схемы. стробы T4 и T5 регулируют, какие именно регистры придут на вход. Надо понимать, что тут просто не нарисованы регистры помимо R1 и R0, но они есть и у каждого из них тоже есть строб, похожий на T4 и T5, если подать сигнал на них, то процессор использует другие регистры при сложении.
Далее T6 - разрешает АЛУ начать свою работу, а через время, "не меньшее чем задержка АЛУ" подается T7 разрешающий запись результата в RC, откуда при помощи стробов T7-T9 мы решаем, куда результат надо записать.
Временная диаграмма следующая:
![[Pasted image 20250101224222.png]]
Еще раз касаясь задержки, она очень сильно зависит от многих факторов, методичка говорит следующее: "Система формирования стробов в процессоре основана на дискретной периодической сетке, формируемой тактовым генератором" (те самые Гигагерцы, которые указывает производитель)
### Операционные устройства с магистральной структурой
То, что мы сверху нарисовали - довольно неудобная конструкция, потому что тянуть 100500 стробов для выбора устройства и дорого и не кайф. Поэтому на практике применяются *операционные устройства (ОПУ)* с магистральной структурой: регистры объединены в *узел регистров общего назначения (узел РОН)*, а все схемы для того, чтобы процессоре делал с данными свои грязные дела в операционный блок (иногда "ассоциируемый" АЛУ).
![[Pasted image 20250101224802.png]]
*Объяснение препода тут чет на сложной терминологии построено, я обойдусь по простяге*
Во-первых единичные проводки в данном случае по всей видимости представляют из себя скорее шины, во-вторых по проводам a, b и с приходят номер регистров, из которых надо почитать или в которые надо записать (нужное подчеркнуть). Все регистры параллельно соединены с обоими мультиплексорами, а те, в свою очередь, по адресу на a и b, решают, в какие из них должны стать аргументами для ОПБ. Когда ОПБ отработал, он весь свой выход подает на демультиплексор, который по адресу в "c" решает, в какой регистр положить результат (все еще держим в голове, что это не один провод, а магистраль и демультиплексор там скорее всего не один)
> [!info]- Примечание о мультиплексорах или демультиплексорах, если забыли
> **Мультиплексор** получает много входов и по входному адресу решает, с какого входа сигнал пропустить дальше, а все остальные сигналы отбрасывает
>
> **Демультиплексор** получает 1 сигнал и при помощи адреса решает, а на какой из множества своих выходов его отправить
### Сопроцессор с плавающей точкой
*Как-нибудь потом при необходимости*
# 3.2 Устройство управления. Микропрограммный автомат
### Устройство управления
%%Пока что нас больше всего интересует именно этот засранец%%
Устройство управления (УУ) - главный дирижёр всего того счастья, которое происходит в процессоре. Именно этот засранец генерирует все те сигналы на стробах, которые вы могли видеть до этого, именно он ответственен за все пересылки между регистрами, инициации записи в оперативу, команды АЛУ выполнять действия над регистрами и за прочие радости жизни. ^0f96bd
> [!warning]+ Я не уверен
> Препод очень криво описал работу УУ, поэтому я, если честно, разбирался по [Википедии](https://ru.wikipedia.org/wiki/%D0%A3%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%BE_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F), поэтому пока что не могу поручиться за качество всего написанного, но вроде описание верное
^cdf8be
На вход УУ принимает следующие параметры:
- Тактовые импульсы (наш любимый clock)
- Коды операций (те самые, которые читаются из оперативы)
- Флаги (нужны для условных переходов например)
- Сигналы системной шины (прерывания, прямой доступ в память, о котором будет сказано, когда мы будем себя мучить переферией, и прочие команды извне)
Выплевывает он следующее:
- Внутренние сигналы управления - перемещение операндов, инициация работы АЛУ %%(похоже везде, где внутри процессора есть стробы управления, за них ответственен именно этот говнюк)%%
- Сигналы на системную шину: тут, как понимаете, ответы на прерывания и запросы, а также возможные переходы между состояниями компа (переход в режим энергосбережения? Не уверен)
Выглядит это все примерно так
![[Pasted image 20250102001212.png]]
Дальше в методичке посыл примерно такой: В каждый отдельно взятый такт процессор выполняет всего одну *микрокоманду* - набор одновременно протекающих *микроопераций*. Последовательность микрокоманд - *микропрограмма*
Микропрограммный автомат - практически процессор в процессоре - сейчас у него буквально есть своя память для микропрограмм, регистры адреса микрокоманды, их дешифрация и прочая радость. Подробнее про микропрограммные автоматы будет оговорено чуть позже
Устройство управления разделяется на 2 части: управляющую и адресную:
- Управляющая занимается координированием работы операционного блока, адресной части, основной памяти и др. При приходе кода операции формирует последовательность микрокоманд и начинает ее исполнять (даже mov rax, rbx переводится в последовательность микрокоманд). Состоит из :
- регистра команд
- микропрограммного автомата (**может быть с жесткой или программируемой логикой**)
- узла прерываний и приоритетов
- Адресная часть обеспечивает формирование адресов операндов в основной памяти. Состоит из:
- операционного узла устройства управления (ОПУУ), который формирует исполнительные адреса операндов команды
- регистра адреса (похоже используется именно для обращения в память, если надо)
- счетчика команд (похоже это rip)
## Типы микропрограммных автоматов
По типу микропрограммного автомата определяется тип всего устройства управления. Есть у нас:
- Микропрограммный автомат с жесткой логикой
- Микропрограммный автомат с программируемой логикой
^CU-types-list
> [!comment]- Примечание билетёра о различиях
> Если не вдаваться в детали, то помогает аналогия из курса схемача. Есть разные виды интегральных схемок.
>
> В первом виде тебе приносят камень, ты один раз загружаешь в него прошивку... и все, он такой на веки вечные и не изменится больше, как ты молоточком не стучи
>
> Во втором виде можно перепрошивать эту плисину сколько угодно раз, хоть до посинения
>
> Так вот, в общем случае первый тип работает намного быстрее и стабильнее, а сами такие чипы получаются дешевле, но при разработке или при ограниченности бюджетов прошивать каждый раз новый кристалл и в случае ошибки его выбрасывать выходит слишком дорого, поэтому разрабатывают на программируемых чипах.
>
> Вот тут ситуация сходная
## Микропрограммный автомат с жесткой логикой
^846e1e
Производитель один раз и на века соединил контакты в логической схеме, что на один и тот же вход процессоры этого аппарата, как бы мы с ними не колдовали, будут выдавать одни и те же сигналы управления
![[Pasted image 20250104190627.png]]
Очевидно, что для той же операции сложения, когда мы смотрели выше на стробы, нам потребовалось существенно больше одного такта, так что здесь помимо кода операции мы постоянно смотрим на то, какой по счету пришел тактовый импульс от начала команды и после реализации всего КОП'а мы сбрасываем счетчик тактов.
*Преподаватель отмечает, что для такой реализации желательно, чтобы для каждого КОП'а был свой собственный вход, чего добиваются дешифратором*
> [!comment]- Комментарий билетёра о "логических схемах формирования сигналов управления"
> В данном случае реализация будет самая лобовая - например у нас есть выходы C1, C2, C3, C4. Мы смотрим берем провод от I1 (на рисунке) и протягиваем сигнал с него во все выходы, на которые он должен повоздействовать, но не просто, а через логическое И, а к этому логическому И протягиваем все тактирующие импульсы T1, T2, T3, на которых сигнал должен дойти до выхода. Все, устройство собрано, а формулау него что-то вроде `C1 = (I1 and T1) or (I1 and T4) or (I3 and T1) or (I3 and T2)`
>
> То есть мы просто протянули все инструкции, которые задействуют выход C1 через такты, на которых эти инструкции должны выдавать 1 и вуа ля, мы собрали простейшую логическую схему (при чем не думаю, что в реальном процессоре все это реализовано сильно иначе)
## Микропрограммный автомат с программируемой логикой
В таком типе автоматов между входом в виде КОП'а и тактовых импульсов, и выходом в виде управляющих сигналов появляется прослойка - **микропрограмма**
В микропрограммном автомате с жесткой логикой мы один раз намертво соединяли контакты, что означает, что последовательность действий для выполнения, например, сложения, надо реализовать аппаратно электрическими схемами, вычитания - тоже логическими схемами. То есть **абсолютно каждая операция в устройстве управления должна быть реализована аппаратно**. В целом сейчас, когда расходы на аппаратные комплектующие относительно маленькие, так и делают, однако в свое время это было неимоверно дорого
Микропрограммы решали эту проблему. Сами по себе они состояли только из узкого набора команд, которые железо могло выполнить напрямую, а в совокупности позволяли выполнять все команды, доступные процессору. Условно появление `shr` запускало целую микропрограмму, которая постепенно передвигала все биты так, чтобы выполнилась команда `shr`. На схеме это выглядит так
![[Pasted image 20250104194436.png]]
^struct-image
*Tут приверду отрывок методички. Он вполне понятно все объясняет*
"Запуск микропрограммы выполнения операции осуществляется путем передачи кода операции из регистра команды на вход преобразователя, в котором код операции (КОП) преобразуется в начальный адрес микропрограммы. Выбранная по этому адресу из памяти микропрограмм микрокоманда заносится в регистр. Микрокоманда содержит КОП и адресную часть. КОП поступает на дешифратор и формирует управляющие сигналы, адрес передается для формирования адреса следующей микрокоманды. Этот адрес может зависеть от флагов, КОП, внешних устройств" ^f2908e
# Пример процессора с 3 шинами и его микропрограммирования
## Микрокоманды и микропрограммы
Микрокоманд в УУ может быть много, но все они, как правило, принадлежат к одному из двух типов:
1. GATE - стробирование (подача управляющих сигналов)
2. TEST - анализа (проверка битов в регистрах)
Все микрокоманды считываются с ПЗУ (обычно встроенного) с тактовой частотой процессора (то есть несколько миллиардов команд в секунду). Размер одной команды называется *словом*.
### Микрокоманда GATE
![[Pasted image 20250105230320.png]]
При выполнении этой команды УУ просто подает соответствующие нули и единицы на свои выходы (по схеме понятно)
### Микрокоманда TEST
![[Pasted image 20250105230420.png]]
### Объем микрокода и размер микрокоманд
Из того, что GATE использует для каждого выхода УУ отдельный бит, можно сделать вывод, что этих битов в этом микропрограммном слове %%термин сам придумал, не используйте%%должно быть никак не меньше, чем количество выходов на процессоре, а также еще один, отведенный под *признак* (голубой квадратик на схемах)
Также необходимо, чтобы в команда TEST могла проверить любой интересующий ее бит в любом регистре. Так что разрядность ограничена снизу еще и этим параметром
На практике оказывается, что дав возможность записать в команду любой набор битов, мы выясняем, что для реализации вообще всего талмуда интел нам требуется, скажем 64 комбинации. Другие мы не использовали ни разу. Встает вопрос - а зачем всю эту радость хранить, это же отжирает у нас место, которое, напомню, дорогое
Поэтому пришли к примерно такой куче мала:
![[Pasted image 20250105232919.png]]
Суть в том, что микрокоды (те самые наборы битов, которых у нас мало, но которые примерно по 100 бит каждое), мы храним в нанопамяти, а в микропамяти мы храним условно "адреса" нужных намкодов в нанопамяти, при этом каждый адрес у нас совсем небольшой (на схеме 6 бит, потому что 64 микрокода в нанопамяти, а $2^{6} = 64$)
## Процессор с тремя внутренними шинами
*Ну вот и то, ради чего мы работали все это время*
![[Pasted image 20250105233200.png]] ^b0a065
Вот эту схему надо запомнить наизусть походу (по крайней мере в билете написано "(схема)")
Вот на этой вот схемке в разных узелочках вы можете видеть стрелочки, над некоторыми даже есть цифры. Так вот, эти стрелочки - проводочки, а эта шняга работает как транзистор - пускает дальше сигнал или не пускает (это на уровне модели, что там препод имел в виду - бог его рассудит)
Далее. Магистрали здесь обозначены AB (A BUS), BB (B BUS), CB (C BUS). Вот этот набор в правом нижнем углу предлагаю считать обрубком нормального АЛУ. (в методичке кстати за АЛУ принят только сумматор, но не суть). Как видно к сумматору стрелки не идет, из чего я предположу, что сложим мы 2 числа вообще в любом случае, а вот подавая единицы на другие стробы в АЛУ можно регулировать, будет ли операция. 0 - не будет, 1 будет. При этом проходить сигнал дальше будет независимо от того, какой сигнал мы подали (тут это не транзистор, это какой-то мультиплексор)
#### Как мы будем эту радость кодить?
А кодить мы это будем, записывая на стробики с какими номерами мы подаем 1, а на какие 0, формируя следующую таблицу
![[Pasted image 20250105233756.png]]
%%Сверху представлена таблица, как можно закодить вычитание на этом обрубке. Тут я этому уделять внимание не буду, это в билете будет нормально написано%%
Как вы понимаете, препод поскупился дать номер вообще всем стробам, поэтому над некоторыми стрелочками номера есть, над другими нет. *Во время ответа на билет, если вы запомнили эту схему повыше, сами там их понумеруйте как вам больше нравится, таблица будет все равно отвратная*

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@ -1,4 +1,6 @@
---
tags:
pun:
pun:
author:
revised:
---