mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 17:20:10 +00:00
Синхронизация с правками публикуемого издания (#101)
* СП. Обновление предисловия * СП. Обновление введения * СП. Обновление лаб * СП. Обновление доп материалов * СП. Введение * СП. Введение * СП. ЛР№4, 15 * СП. Базовые конструкции Verilog * Update Implementation steps.md * СП. ЛР 4,5,7,8,14 * СП. ЛР№8 * Синхронизация правок * СП. Финал * Исправление ссылки на рисунок * Обновление схемы * Синхронизация правок * Добавление белого фона .drawio-изображениям * ЛР2. Исправление нумерации рисунка
This commit is contained in:
committed by
GitHub
parent
d251574bbc
commit
9739429d6e
@@ -36,7 +36,7 @@
|
||||
4. изменяется значение `PC`;
|
||||
5. цикл повторяется с `п.1`.
|
||||
|
||||
Любая инструкция приводит к изменению состояния памяти. В случае процессора с архитектурой `CYBERcobra 3000 Pro 2.1` есть два класса инструкций: одни изменяют содержимое регистрового файла — это инструкции записи. Другие изменяют значение `PC` — это инструкции перехода. В первом случае используются вычислительные инструкции и инструкции загрузки данных из других источников. Во-втором случае используются инструкции перехода.
|
||||
Любая инструкция приводит к изменению состояния памяти. В случае процессора с архитектурой `CYBERcobra 3000 Pro 2.1` есть два класса инструкций: одни изменяют содержимое регистрового файла — это инструкции записи. Другие изменяют значение `PC` — это инструкции перехода. В первом случае используются вычислительные инструкции и инструкции загрузки данных из других источников. Во втором случае используются инструкции перехода.
|
||||
|
||||
Если процессор обрабатывает вычислительную инструкцию, то `PC` перейдет к следующей по порядку инструкции. В ЛР№3 мы реализовали память инструкций с [побайтовой адресацией](../03.%20Register%20file%20and%20memory/README.md#1-память-инструкций). Это означает, что каждый байт памяти имеет свой собственный адрес. Поскольку длина инструкции составляет `4 байта`, для перехода к следующей инструкции `PC` должен быть увеличен на `4` (`PC = PC + 4`). При этом, регистровый файл сохранит результат некоторой операции на АЛУ или данные с порта входных данных.
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
Так как операции будут выполняться только над данными в регистровом файле, то его можно сразу подключить к АЛУ, соединив порты чтения `read_data1_o` и `read_data2_o` со входами операндов АЛУ, а результат операции АЛУ подключив к порту на запись `write_data_i`. Полученный результат изображен на _рис. 0_.
|
||||
|
||||
> Для того, чтобы номера таблиц и рисунков лучше соотносились друг с другом и сопутствующим текстом, первая схема разрабатываемой микроархитектуры будет обозначена как _Рисунок 0_. Все последующие схемы будут совпадать по нумерации с таблицами, обозначающими способ кодирования инструкций.
|
||||
> Для того чтобы номера таблиц и рисунков лучше соотносились друг с другом и сопутствующим текстом, первая схема разрабатываемой микроархитектуры будет обозначена как _Рисунок 0_. Все последующие схемы будут совпадать по нумерации с таблицами, обозначающими способ кодирования реализуемого типа инструкций.
|
||||
|
||||

|
||||
|
||||
@@ -107,14 +107,24 @@ _Таблица 1. Кодирование вычислительных инст
|
||||
|
||||
### Реализация вычислительных инструкций
|
||||
|
||||
Чтобы процессор правильно реагировал на эти инструкции, требуется подключить ко входам адреса регистрового файла и управляющему входу АЛУ соответствующие биты выхода `read_data_o` памяти инструкции (**Instruction Memory**). В таком случае, когда `PC` будет указывать на ячейку памяти, в которой лежит, например, следующая 32-битная инструкция:
|
||||
Чтобы процессор правильно реагировал на эти инструкции, требуется подключить ко входам адреса регистрового файла и управляющему входу АЛУ соответствующие биты выхода `read_data_o` памяти инструкции (**Instruction Memory**). Допустим, программный счётчик указывает на ячейку памяти, в которой хранится следующая 32-битная инструкция:
|
||||
|
||||
```text
|
||||
0000 00111 00100 01000 00000000 11100
|
||||
0000|00111 |00100|01000|00000000|11100
|
||||
|alu_op| RA1 | RA2 | | WA
|
||||
```
|
||||
|
||||
будет выполнена операция `reg_file[28] = reg_file[4] | reg_file[8]`, потому что `alu_op = 00111`, что соответствует операции **логического ИЛИ** (см ЛР№2), `WA = 11100`, то есть запись произойдёт в 28-ой регистр, `RA1 = 00100` и `RA2 = 01000` — это значит что данные для АЛУ будут браться из 4-го и 8-го регистров соответственно.
|
||||
В этом случае, будет выполнена операция:
|
||||
|
||||
```text
|
||||
reg_file[28] = reg_file[4] | reg_file[8]
|
||||
```
|
||||
|
||||
Здесь:
|
||||
|
||||
- `alu_op = 00111`, что соответствует операции **логического ИЛИ** (см ЛР№2);
|
||||
- `WA = 11100`, то есть запись произойдёт в 28-ой регистр;
|
||||
- `RA1 = 00100` и `RA2 = 01000` — это значит что данные для АЛУ будут браться из 4-го и 8-го регистров соответственно.
|
||||
|
||||
_Рис. 1_ иллюстрирует фрагмент микроархитектуры, поддерживающий вычислительные операции на АЛУ. Поскольку другие инструкции пока что не поддерживаются, то вход `WE` регистрового файла просто равен `1` (это временно).
|
||||
|
||||
@@ -124,7 +134,7 @@ _Рисунок 1. Подключение АЛУ и регистрового ф
|
||||
|
||||
### Реализация загрузки константы в регистровый файл
|
||||
|
||||
Информация как-то должна попадать в регистровый файл, для этого добавим инструкцию загрузки константы по адресу `WA`. Чтобы аппаратура могла различать, когда ей нужно выполнять операцию на АЛУ, а когда загружать константу, назначим один бит инструкции определяющим "что именно будет записано в регистровый файл": результат с АЛУ или константа из инструкции. За это будет отвечать 28-ой бит инструкции `WS` (**Write Source**). Если `WS == 1`, значит выполняется вычислительная инструкция, а если `WS == 0`, значит нужно загрузить константу в регистровый файл.
|
||||
Обрабатываемая информация как-то должна попадать в регистровый файл, для этого добавим инструкцию загрузки константы по адресу `WA`. Чтобы аппаратура могла различать, когда ей нужно выполнять операцию на АЛУ, а когда загружать константу, назначим один бит инструкции определяющим "что именно будет записано в регистровый файл": результат с АЛУ или константа из инструкции. За это будет отвечать 28-ой бит инструкции `WS` (**Write Source**). Если `WS == 1`, значит выполняется вычислительная инструкция, а если `WS == 0`, значит нужно загрузить константу в регистровый файл.
|
||||
|
||||
Сама константа имеет разрядность **23 бита** ([27:5] биты инструкции) и должна быть **знакорасширена** до 32-х бит, то есть к 23-битной константе нужно приклеить слева 9 раз 23-ий знаковый бит константы (см. [оператор конкатенации](../../Basic%20Verilog%20structures/Concatenation.md)).
|
||||
|
||||
@@ -169,7 +179,7 @@ _Рисунок 2. Добавление константы из инструкц
|
||||
|
||||
### Реализация загрузки в регистровый файл данных с внешних устройств
|
||||
|
||||
Чтобы процессор мог взаимодействовать с внешним миром добавим возможность загрузки данных с внешних устройств в регистр по адресу `WA`. Появляется третий тип инструкции, который определяет третий источник ввода для регистрового файла. Одного бита `WS` для выбора одного из трех источников будет недостаточно, поэтому расширим это поле до 2 бит. Теперь, когда `WS == 0` будет загружаться константа, когда `WS == 1` – будет загружаться результат вычисления АЛУ, а при `WS == 2` будут загружаться данные с внешних устройств. Остальные поля в данной инструкции не используются.
|
||||
Чтобы процессор мог взаимодействовать с внешним миром добавим возможность загрузки данных с внешних устройств в регистр по адресу `WA`. Появляется третий тип инструкции, который определяет третий источник ввода для регистрового файла. Одного бита `WS` для выбора одного из трех источников будет недостаточно, поэтому расширим это поле до 2 бит. Теперь, когда `WS == 0` будет загружаться константа, когда `WS == 1` – будет загружаться результат вычисления АЛУ, а при `WS == 2` будут загружаться данные с внешних устройств. Остальные поля (кроме `WA`) в данной инструкции не используются.
|
||||
|
||||

|
||||
|
||||
@@ -183,7 +193,7 @@ _Таблица 3. Кодирование в инструкции большег
|
||||
|
||||
По аналогии с загрузкой констант увеличиваем входной мультиплексор до 4 входов и подключаем к нему управляющие сигналы – `[29:28]` биты инструкции. Последний вход используется, чтобы разрешить неопределённость на выходе при `WS == 3`(`default`-вход, см. [мультиплексор](../../Basic%20Verilog%20structures/Multiplexors.md)).
|
||||
|
||||
Выход OUT подключается к первому порту на чтение регистрового файла. Значение на выходе OUT будет определяться содержимым ячейки памяти по адресу `RA1`.
|
||||
Выход модуля `out_o` подключается к первому порту на чтение регистрового файла. Значение на выходе `out_o` будет определяться содержимым ячейки памяти по адресу `RA1`.
|
||||
|
||||

|
||||
|
||||
@@ -199,9 +209,9 @@ _Таблица 4.Кодирование условного перехода._
|
||||
|
||||
Для вычисления результата условного перехода, нам необходимо выполнить операцию на АЛУ и посмотреть на сигнал `flag`. Если он равен 1, переход выполняется, в противном случае — не выполняется. А значит, нам нужны операнды `A`, `B`, и `alu_op`. Кроме того, нам необходимо указать насколько мы сместимся относительно текущего значения `PC` (константу смещения, `offset`). Для передачи этой константы лучше всего подойдут незадействованные биты инструкции `[12:5]`.
|
||||
|
||||
Обратим внимание на то, что `PC` 32-битный и должен быть всегда кратен четырем (`PC` не может указывать кроме как в начало инструкции, а каждая инструкция длиной в 32 бита). Кратные четырем двоичные числа всегда будут иметь в конце два нуля (так же, как и кратные ста десятичные числа). Поэтому для более эффективного использования бит константы смещения, эти два нуля будут неявно подразумеваться при её описании. При этом, перед увеличением программного счётчика на значение константы смещения, эти два нуля нужно будет к ней приклеить справа. Кроме того, чтобы разрядность константы совпадала с разрядностью `PC`, необходимо знакорасширить её до 32 бит.
|
||||
Обратим внимание на то, что `PC` 32-битный и должен быть всегда кратен четырем (`PC` не может указывать кроме как в начало инструкции, а каждая инструкция длиной в 32 бита). Кратные четырем двоичные числа всегда будут иметь в конце два нуля (так же, как и кратные ста десятичные числа). Поэтому для более эффективного использования битов константы смещения, эти два нуля будут неявно подразумеваться при её описании. При этом, перед увеличением программного счётчика на значение константы смещения, эти два нуля нужно будет к ней приклеить справа. Кроме того, чтобы разрядность константы совпадала с разрядностью `PC`, необходимо знакорасширить её до 32 бит.
|
||||
|
||||
Предположим, мы хотим переместиться на две инструкции вперед. Это означает, что программный счётчик должен будет увеличиться на 8 ([2 инструкции] * [4 байта — размер одной инструкции в памяти]). Умножение на 4 константы смещения произойдет путем добавления к ней двух нулей справа, поэтому в поле `offset` мы просто записываем число инструкций, на которые мы переместим программный счётчик (на две): `0b00000010`.
|
||||
Предположим, мы хотим переместиться на две инструкции вперед. Это означает, что программный счётчик должен будет увеличиться на 8 ([2 инструкции] * [4 байта — размер одной инструкции в памяти]). Умножение константы смещения на 4 произойдет путем добавления к ней двух нулей справа, поэтому в поле `offset` мы просто записываем число инструкций, на которое мы переместим программный счётчик (на две): `0b00000010`.
|
||||
|
||||
Данный Си-подобный псевдокод (далее мы назовем его псевдоассемблером) демонстрирует кодирование инструкций с новым полем `B`:
|
||||
|
||||
@@ -214,7 +224,7 @@ _Таблица 4.Кодирование условного перехода._
|
||||
|
||||
Так как второй вход сумматора счётчика команд занят числом 4, то для реализации условного перехода этот вход надо мультиплексировать с константой. Мультиплексор при этом управляется 30-ым битом `B`, который и определяет, что будет прибавляться к `PC`.
|
||||
|
||||
Сигнальные линии, которые управляют АЛУ и подают на его входы операнды уже существуют. Поэтому на схему необходимо добавить только логику управления мультиплексором на входе сумматора счётчика команд так. Эта логика работает следующим образом:
|
||||
Сигнальные линии, которые управляют АЛУ и подают на его входы операнды уже существуют. Поэтому на схему необходимо добавить только логику управления мультиплексором на входе сумматора счётчика команд. Эта логика работает следующим образом:
|
||||
|
||||
1. если сейчас инструкция условного перехода
|
||||
2. и если условие перехода выполнилось,
|
||||
@@ -241,11 +251,10 @@ _Таблица 5. Кодирование безусловного перехо
|
||||
|
||||
Для реализации безусловного перехода, нам необходимо добавить дополнительную логику управления мультиплексором перед сумматором. Итоговая логика его работы звучит так:
|
||||
|
||||
1. Если сейчас инструкция безусловного перехода
|
||||
2. ИЛИ если сейчас инструкция условного перехода
|
||||
3. И если условие перехода выполнилось
|
||||
1. если сейчас инструкция безусловного перехода, _или_
|
||||
2. если сейчас инструкция условного перехода _и_ условие перехода выполнилось
|
||||
|
||||
Кроме того, при безусловном переходе в регистровый файл так же ничего не пишется. А значит, необходимо обновить логику работы сигнала разрешения записи `WE`, который будет равен 0 если сейчас инструкция условного или безусловного перехода.
|
||||
Кроме того, при безусловном переходе в регистровый файл также ничего не пишется. А значит, необходимо обновить логику работы сигнала разрешения записи `WE`, который будет равен 0 если сейчас инструкция условного или безусловного перехода.
|
||||
|
||||
На _рис. 5_ приводится итоговый вариант микроархитектуры процессора `CYBERcobra 3000 Pro 2.1`.
|
||||
|
||||
@@ -255,7 +264,7 @@ _Рисунок 5. Реализация безусловного переход
|
||||
|
||||
### Финальный обзор
|
||||
|
||||
Итого, архитектура `CYBERcobra 3000 Pro 2.1` поддерживает 5 типов инструкций, которые кодируются следующим образом (иксами помечены биты, которые не задействованы в данной инструкции):
|
||||
Итого, архитектура `CYBERcobra 3000 Pro 2.1` поддерживает 5 типов инструкций, которые кодируются следующим образом (символами `x` помечены биты, которые не задействованы в данной инструкции):
|
||||
|
||||
1. 10 вычислительных инструкций `0 0 01 alu_op RA1 RA2 xxxx xxxx WA`
|
||||
2. Инструкция загрузки константы `0 0 00 const WA`
|
||||
@@ -265,9 +274,9 @@ _Рисунок 5. Реализация безусловного переход
|
||||
|
||||
При кодировании инструкций используются следующие поля:
|
||||
|
||||
- J – однобитный сигнал, указывающий на выполнение безусловного перехода;
|
||||
- B – однобитный сигнал, указывающий на выполнение условного перехода;
|
||||
- WS – двухбитный сигнал, указывающий источник данных для записи в регистровый файл:
|
||||
- J – 1-битный сигнал, указывающий на выполнение безусловного перехода;
|
||||
- B – 1-битный сигнал, указывающий на выполнение условного перехода;
|
||||
- WS – 2-битный сигнал, указывающий источник данных для записи в регистровый файл:
|
||||
- 0 – константа из инструкции;
|
||||
- 1 – результат с АЛУ;
|
||||
- 2 – внешние данные;
|
||||
@@ -281,9 +290,9 @@ _Рисунок 5. Реализация безусловного переход
|
||||
Напишем простую программу для этого процессора, которая циклично увеличивает значение первого регистра на 1 до тех пор, пока его значение не превысит число, введенное на переключателях. Сначала напишем программу на псевдоассемблере (используя предложенную мнемонику):
|
||||
|
||||
``` C
|
||||
reg_file[1] ← -1 // загрузить константу `-1` регистр 1
|
||||
reg_file[1] ← -1 // загрузить константу -1 в регистр 1
|
||||
reg_file[2] ← sw_i // загрузить значение с входа sw_i в регистр 2
|
||||
reg_file[3] ← 1 // загрузить константу `1` регистр 3
|
||||
reg_file[3] ← 1 // загрузить константу 1 в регистр 3
|
||||
|
||||
reg_file[1] ← reg_file[1] + reg_file[3] // сложить регистр 1 с регистром 3 и
|
||||
// поместить результат в регистр 1
|
||||
@@ -344,17 +353,17 @@ endmodule
|
||||
1. В первую очередь, необходимо создать счётчик команд и все вспомогательные провода. При создании, **следите за разрядностью**.
|
||||
2. Затем, необходимо создать экземпляры модулей: памяти инструкции, АЛУ, регистрового файла и сумматора. При подключении сигналов сумматора, надо **обязательно** надо подать нулевое значение на входной бит переноса. Выходной бит переноса подключать не обязательно. Объекту памяти инструкций нужно дать имя `imem`.
|
||||
3. После этого, необходимо описать оставшуюся логику:
|
||||
1. Программного счётчика
|
||||
1. Программного счётчика. Счётчик должен сбрасываться, когда сигнал _rst_i == 1_.
|
||||
2. Сигнала управления мультиплексором, выбирающим слагаемое для программного счётчика
|
||||
3. Сигнала разрешения записи в регистровый файл
|
||||
4. Мультиплексор, выбирающий слагаемое для программного счётчика
|
||||
5. Мультиплексор, выбирающий источник записи в регистровый файл.
|
||||
3. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_04.tb_cybercobra.sv`](lab_04.tb_cybercobra.sv).
|
||||
1. Перед запуском моделирования, убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
||||
2. В этот раз, в конце не будет сообщения о том, работает ли ваше устройство или в нем есть ошибки. Вам необходимо самостоятельно проверить работу модуля, перенеся его внутренние сигналы на временную диаграмму, и [изучив](../../Vivado%20Basics/05.%20Bug%20hunting.md) их поведение.
|
||||
2. В этот раз, в конце не будет сообщения о том, работает ли ваше устройство или в нём есть ошибки. Вам необходимо самостоятельно проверить работу модуля, перенеся его внутренние сигналы на временную диаграмму, и [изучив](../../Vivado%20Basics/05.%20Bug%20hunting.md) их поведение.
|
||||
3. По сути, проверка сводится к потактовому изучению временной диаграммы, во время которого вам нужно циклично ответить на следующие вопросы (после чего необходимо сравнить предсказанный ответ со значением сигналов на временной диаграмме):
|
||||
1. Какое сейчас значение программного счётчика?
|
||||
2. Какое должно быть значение у ячейки памяти инструкций с адресом, соответствующим значению программного счётчика. Какой инструкции соответствует значение этой ячейки памяти?
|
||||
2. Какая инструкция должна быть считана при данном значении программного счётчика?
|
||||
3. Как должно обновиться содержимое регистрового файла в результате выполнения этой инструкции: должно ли записаться какое-либо значение? Если да, то какое и по какому адресу?
|
||||
4. Как должен измениться программный счётчик после выполнения этой инструкции?
|
||||
4. Проверьте работоспособность вашей цифровой схемы в ПЛИС.
|
||||
|
Reference in New Issue
Block a user