# Лабораторная работа 7 "Внешняя память"

Ранее вы реализовали процессор архитектуры RISC-V с оговоркой что он не поддерживает инструкции `sh`, `sb`, `lh`, `lhu`, `lb`, `lbu`. Данное ограничение имеет две причины:

- вам нужен модуль, который будет определенным образом взаимодействовать с памятью в зависимости от конкретной инструкции загрузки или сохранения (**модуль загрузки и сохранения**, о котором будет рассказано на [следующей](../08.%20Load-store%20unit) лабораторной работе);
- вам нужна внешняя память, которая будет способна делать то, что от нее запросит модуль загрузки и сохранения.

Реализации такой памяти и будет посвящена эта лабораторная работа.

## Цель

Описать внешнюю память данных, полностью поддерживающую побайтовую адресацию.

## Допуск к лабораторной работе

Для успешного выполнения лабораторной работы, вам необходимо:

- выполнить [лабораторную работу №3](../03.%20Register%20file%20and%20memory/) "Регистровый файл и внешняя память";
- освоить оператор конкатенации ([Concatenation.md](../../Basic%20Verilog%20structures/Concatenation.md)).

## Теория

В задании по реализации памяти инструкций [лабораторной работы №3](../03.%20Register%20file%20and%20memory/) байтовая адресация была описана следующим образом:

> Байтовая адресация означает, что процессор способен обращаться к отдельным байтам в памяти (за каждым байтом памяти закреплен свой индивидуальный адрес).

Данное описание было дано не совсем корректным образом, чтобы в третьей лабораторной работе было более четкое понимание задания. В чем заключается некорректность? Процессор должен быть способен не только **обращаться** к отдельным байтам в памяти, но и **обновлять** в памяти любой отдельный байт, а также **считывать** отдельные байты.

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

Нас интересует возможность памяти обновлять любой из байт в слове. Для этого используется специальный сигнал, который называется `byte_enable_i`. Разрядность этого сигнала равна числу байт в ячейке памяти (в данном случае разрядность `byte_enable_i` составляет 4). Вы можете представить `byte_enable_i`, как 4 провода, каждый из которых является сигналом разрешения записи для 8-ми D-триггеров, формирующих соответствующий этому проводу байт.

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

Таким образом, для каждого байта `addr_i / 4`-ой ячейки памяти:

**если** `write_enable_i` равен единице **и** соответствующий этому байту бит сигнала `byte_enable_i`, то в данный байт памяти записывается соответствующий байт сигнала `write_data_i`.

При этом значение `byte_enable_i` может быть любым: если `byte_enable_i == 4'b1001` (при `write_enable == 1'b1`),  то данные должны быть записаны в старший и младший байты `addr_i / 4`-ой ячейки памяти.

## Задание

Реализовать память данных с поддержкой обновления отдельных байт в выбранной ячейке памяти. Прототип модуля следующий (обратите внимание что название модуля отличается от названия памяти данных из третьей лабораторной работы — так мы сможем различать их):

```SystemVerilog
module ext_mem(
  input  logic        clk_i,
  input  logic        mem_req_i,
  input  logic        write_enable_i,
  input  logic [ 3:0] byte_enable_i,
  input  logic [31:0] addr_i,
  input  logic [31:0] write_data_i,
  output logic [31:0] read_data_o,
  output logic        ready_o
);
```

Как и память данных из лабораторной работы №3, память данных в данной лабораторной состоит из 4096-и 32-разрядных ячеек и обладает портом синхронного чтения, обновляющим данные только по запросу на чтение (`mem_req_i & !write_enable_i`).

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

Если `mem_req_i == 1` и `write_enable_i == 1` (т.е. если происходит запрос на запись в память), то необходимо обновить данные в тех байтах `addr_i / 4`-ой ячейки памяти, которые соответствуют единичным битам сигнала `byte_enable_i`.

Сигнал `ready_o` тождественно равен единице.

## Порядок выполнения работы

1. Внимательно ознакомьтесь с заданием. В случае возникновения вопросов, проконсультируйтесь с преподавателем.
2. Реализуйте память данных. Для этого:
   1. В `Design Sources` проекта создайте `SystemVerilog`-файл `ext_mem.sv`.
   2. Опишите в нем модуль памяти данных с таким же именем и портами, как указано в задании.
      1. Данный модуль будет очень похож на память данных из лабораторной работы №3 (в частности, логика порта на чтение будет в точности повторять логику той памяти данных).
      2. Отличие заключается в двух новых сигналах `ready_o` и `byte_enable_i`.
         1. Сигнал `ready_o` тождественно равен единице.
         2. Сигнал `byte_enable_i` используется в качестве сигнала, разрешающего запись (в случае операции записи) в конкретный байт ячейки памяти.
   3. После описания памяти данных, её необходимо проверить с помощью тестового окружения.
      1. Тестовое окружение находится [`здесь`](tb_ext_mem.sv).
      2. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
      3. Перед запуском симуляции убедитесь, что в качестве top-level модуля выбран корректный (`tb_ext_mem`).
      4. **Во время симуляции, вы должны прожать "Run All" и убедиться, что в логе есть сообщение о завершении теста!**
