Синхронизация с правками публикуемого издания (#101)

* СП. Обновление предисловия

* СП. Обновление введения

* СП. Обновление лаб

* СП. Обновление доп материалов

* СП. Введение

* СП. Введение

* СП. ЛР№4, 15

* СП. Базовые конструкции Verilog

* Update Implementation steps.md

* СП. ЛР 4,5,7,8,14

* СП. ЛР№8

* Синхронизация правок

* СП. Финал

* Исправление ссылки на рисунок

* Обновление схемы

* Синхронизация правок

* Добавление белого фона .drawio-изображениям

* ЛР2. Исправление нумерации рисунка
This commit is contained in:
Andrei Solodovnikov
2025-02-12 17:53:52 +03:00
committed by GitHub
parent d251574bbc
commit 9739429d6e
168 changed files with 79781 additions and 961 deletions

View File

@@ -1,6 +1,6 @@
# Лабораторная работа №8 "Блок загрузки и сохранения"
Итогом шестой лабораторной работы стал практически завершенный процессор архитектуры RISC-V. Особенностью реализации процессора было отсутствие поддержки инструкций `LB`, `LBU`, `SB`, `LH`, `LHU`, `SH`. Тому было две причины:
Итогом седьмой лабораторной работы стал практически завершенный процессор архитектуры RISC-V. Особенностью реализации процессора было отсутствие поддержки инструкций `LB`, `LBU`, `SB`, `LH`, `LHU`, `SH`. Тому было две причины:
- подключенный к памяти данных сигнал `byte_enable_i` был аппаратно зафиксирован на значении `4'b1111`, но на самом деле этим сигналом должен кто-то управлять;
- необходимо подготовить считанные из памяти полуслова / байты для записи в регистровый файл.
@@ -35,9 +35,9 @@ _Рисунок 1. Место LSU в микроархитектуре RISC-пр
### Интерфейс процессора и блока загрузки/сохранения
На входной порт `core_addr_i` от процессора поступает адрес ячейки памяти, к которой будет произведено обращение. Намеренье процессора обратиться к памяти (и для чтения, и для записи) отражается выставлением сигнала `core_req_i` в единицу. Если процессор собирается записывать в память, то сигнал `core_we_i` выставляется в единицу, а сами данные, которые следует записать, поступают от него на вход `core_wd_i`. Если процессор собирается читать из памяти, то сигнал `core_we_i` находится в нуле, а считанные данные подаются для процессора на выход `core_rd_o`.
На входной порт `core_addr_i` от процессора поступает адрес ячейки памяти, к которой будет произведено обращение. Намеренье процессора обратиться к памяти (как для чтения, так и для записи) отражается выставлением сигнала `core_req_i` в единицу. Если процессор собирается записывать в память, то сигнал `core_we_i` выставляется в единицу, а сами данные, которые следует записать, поступают от него на вход `core_wd_i`. Если процессор собирается читать из памяти, то сигнал `core_we_i` находится в нуле, а считанные данные подаются на выход `core_rd_o`.
Инструкции `LOAD` и `STORE` в **RV32I** поддерживают обмен 8-битными, 16-битными или 32-битными значениями, однако в самом процессоре происходит работа только с 32-битными числами, поэтому загружаемые из памяти байты и послуслова необходимо предварительно расширить до 32-битного значения. Расширять значения можно либо знаковым битом, либо нулями — в зависимости от того как должно быть интерпретировано загружаемое число: как знаковое или беззнаковое. Во время записи данных в память, они не расширяются, поскольку в отличие от регистрового файла, основная память имеет возможность обновлять отдельные байты. Таким образом, различать знаковые и беззнаковые числа необходимо только на этапе загрузки, но не сохранения.
Инструкции `LOAD` и `STORE` в **RV32I** поддерживают обмен 8-битными, 16-битными или 32-битными значениями, однако в самом процессоре происходит работа только с 32-битными числами, поэтому загружаемые из памяти байты и послуслова необходимо предварительно расширить до 32-битного значения. Расширять значения можно либо знаковым битом, либо нулями — в зависимости от того, как должно быть интерпретировано загружаемое число: как знаковое или беззнаковое. Во время записи данных в память, они не расширяются, поскольку в отличие от регистрового файла, основная память имеет возможность обновлять отдельные байты. Таким образом, различать знаковые и беззнаковые числа необходимо только на этапе загрузки, но не сохранения.
Для выбора разрядности и формата представления числа, на вход **LSU** подаётся сигнал `core_size_i`, принимающий следующие значения (для удобства использования, данные значения определены в виде параметров в пакете `decoder_pkg`):
@@ -55,7 +55,7 @@ _Рисунок 1. Место LSU в микроархитектуре RISC-пр
### Интерфейс блока загрузки/сохранения и памяти
Память данных имеет 32-битную разрядность ячейки памяти и поддерживает побайтовую адресацию. Это значит, что существует возможность обновить любой байт пределах одного слова (4-байтовой ячейки памяти), не изменяя слова целиком. Для указания на обновляемые байты интерфейс к памяти предусматривает использование 4-битного сигнала `mem_be_o`, подаваемого вместе с адресом слова `mem_addr_o`. Позиции битов 4-битного сигнала соответствуют позициям байт в слове. Если конкретный бит `mem_be_o` равен 1, то соответствующий ему байт в памяти будет обновлен. Данные для записи подаются на выход `mem_wd_o`. На результат чтения из памяти состояние `mem_be_o` не влияет, так как чтение производится всегда по 32-бита.
Память данных имеет 32-битную разрядность ячейки памяти и поддерживает побайтовую адресацию. Это значит, что существует возможность обновить любой байт в пределах одного слова (4-байтовой ячейки памяти), не изменяя слова целиком. Для указания на обновляемые байты интерфейс к памяти предусматривает использование 4-битного сигнала `mem_be_o`, подаваемого вместе с адресом слова `mem_addr_o`. Позиции битов 4-битного сигнала соответствуют позициям байт в слове. Если конкретный бит `mem_be_o` равен 1, то соответствующий ему байт в памяти будет обновлен. Данные для записи подаются на выход `mem_wd_o`. На результат чтения из памяти состояние `mem_be_o` не влияет, так как чтение производится всегда по 32-бита.
После получения запроса на чтение/запись из ядра **LSU** перенаправляет запрос в память данных, взаимодействие осуществляется следующими сигналами:
@@ -110,7 +110,7 @@ _Рисунок 1. Место LSU в микроархитектуре RISC-пр
### mem_be_o
Данный сигнал принимает ненулевые значения только по запросу на запись (`core_req_i == 1`, `core_we_i == 1`), во время которого происходит мультиплексирование сигнала `core_size_i`. Если `core_size_i` соответствует инструкции записи байта (`LDST_B`, 3'd0), то в сигнале `mem_be_o` бит с индексом равным значению двух младших бит адреса `core_addr_i` должен быть равен единице.
Данный сигнал является результатом мультиплексирования с управляющим сигналом `core_size_i`. Если `core_size_i` соответствует инструкции записи байта (`LDST_B`, 3'd0), то в сигнале `mem_be_o` бит с индексом равным значению двух младших бит адреса `core_addr_i` должен быть равен единице.
Допустим, пришёл запрос на запись байта по адресу 18:
@@ -164,7 +164,7 @@ _Рисунок 3. Временна́я диаграмма запросов на
Предположим, по адресам `16-19` лежит слово `32'hA55A_1881` (см. _рис. 4_). Чтение по любому из адресов 16, 17, 18, 19 вернет это слово на входном сигнале `mem_rd_i`. В случае инструкции `LB` (чтение байта, который интерпретируется как знаковое число, во время которого `core_size_i == LDST_B`) по адресу 19, в регистровый файл должно быть записано значение `32'hFFFF_FFA5`, поскольку по 19-ому адресу лежит байт `A5`, который затем будет знакорасширен. В случае той же самой инструкции, но по адресу 18, в регистровый файл будет записано значение `32'h0000_005A` (знакорасширенный байт `5A`, расположенный по 18ому адресу).
Получить нужный байт можно из входного сигнала `mem_rd_i`, но чтобы понять какие биты этого сигнала нас интересуют, необходимо посмотреть на входные сигналы `core_size_i` и `core_addr_i[1:0]`. `core_size_i` сообщит конкретный тип инструкции (сколько нужно взять байт из считанного слова), а `core_addr_i[1:0]` укажет номер начального байта, который нужно взять из `mem_rd_i`.
Получить нужный байт можно из входного сигнала `mem_rd_i`, но чтобы понять какие биты этого сигнала нас интересуют, необходимо посмотреть на входные сигналы `core_size_i` и `core_addr_i[1:0]`. `core_size_i` сообщит размер порции данных (сколько нужно взять байт из считанного слова), а `core_addr_i[1:0]` укажет номер байта в `mem_rd_i`, с которого эта порция данных начинается..
В случае инструкции `LH` будет все тоже самое, только знакорасширяться будет не байт, а полуслово.