From 25804e7b812384cbf2096952789e7645f54227cf Mon Sep 17 00:00:00 2001 From: Andrei Solodovnikov Date: Mon, 15 Jul 2024 16:48:40 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9B=D0=A06.=20=D1=81=D1=82=D0=B8=D0=BB=D0=B8?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B5=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pic/Labs/lab_06_main_memory/fig_03.wavedrom.svg | 2 +- Labs/06. Main memory/README.md | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.pic/Labs/lab_06_main_memory/fig_03.wavedrom.svg b/.pic/Labs/lab_06_main_memory/fig_03.wavedrom.svg index 30cf9d4..d30ed1f 100644 --- a/.pic/Labs/lab_06_main_memory/fig_03.wavedrom.svg +++ b/.pic/Labs/lab_06_main_memory/fig_03.wavedrom.svg @@ -1,4 +1,4 @@ -clkmem_req_iaddr_i0x80x90x40x60xCwrite_enable_ibyte_enable_i0b11110b00100b00110b11000b1111write_data_i0xDEAD_BEEF0x5555_55550xFACE_FACE0xBABE_BABE0x00000000mem[addr]0x000000000xDEAD_BEEF0xDEAD_55EF0xDEAD_FACE0xBABE_FACE0x00000000 \ No newline at end of file +clkmem_req_iaddr_i0x80x90x80xA0x8write_enable_ibyte_enable_i0b11110b00100b00110b11000b1111write_data_i0xDEAD_BEEF0x5555_55550xFACE_FACE0xBABE_BABE0x00000000mem[2]0x000000000xDEAD_BEEF0xDEAD_55EF0xDEAD_FACE0xBABE_FACE0x00000000 \ No newline at end of file diff --git a/Labs/06. Main memory/README.md b/Labs/06. Main memory/README.md index de7f4f9..dd14ba0 100644 --- a/Labs/06. Main memory/README.md +++ b/Labs/06. Main memory/README.md @@ -20,13 +20,13 @@ Вопрос считывания отдельного байта будет решаться специальным модулем **загрузки и сохранения**, памяти данных при этом будет достаточно возвращать всё слово, содержащее запрашиваемый байт как это было уже делалось для памяти инструкций. -Нас интересует возможность памяти обновлять любой из байт в слове. Подобный функционал часто используется при реализации памяти и в системных интерфейсах, например AXI4 или APB. Для этого используется специальный сигнал, который называется `byte enable`. Разрядность этого сигнала равна числу байт в шине данных (в нашем случае разрядность `byte enable` составляет 4). Вы можете представить этот сигнал, как 4 провода, каждый из которых является сигналом разрешения записи для отдельной памяти с шириной данный в 1 байт. +Нас интересует возможность памяти обновлять любой из байт в слове. Подобный функционал часто используется при реализации памяти и в системных интерфейсах, например AXI4 или APB. Для этого используется специальный сигнал, который называется `byte enable`. Разрядность этого сигнала равна числу байт в шине данных (в нашем случае разрядность `byte enable` составляет 4). Вы можете представить этот сигнал, как 4 провода, каждый из которых является сигналом разрешения записи для отдельной памяти с шириной данных в 1 байт. -Давайте разберемся как это будет работать. Допустим, мы хотим записать значение `0xA5` по адресу `0x6`. Поскольку мы работаем с байтовой адресацией, как и при реализации памяти инструкций, пришедший адрес необходимо будет разделить на 4 (см. _рис. 1_). В итоге мы получим указатель на первую 32-битную ячейку памяти (`6 / 4 = 1`). Однако, чтобы пришедшие данные были в итоге записаны не в нулевой байт первого слова (четвертый байт памяти), во второй, мы будем использовать сигнал `byte enable`, второй бит которого будет равен единице. +Давайте разберемся как это будет работать. Допустим, мы хотим записать значение `0xA5` по адресу `0x6`. Поскольку мы работаем с байтовой адресацией, а ячейки памяти 32-битные — как и при реализации памяти инструкций, пришедший адрес необходимо будет разделить на 4 (см. _рис. 1_). В итоге мы получим указатель на первую 32-битную ячейку памяти (`6 / 4 = 1`). Однако, чтобы пришедшие данные были в итоге записаны не в нулевой байт первого слова (четвертый байт памяти), а во второй, мы будем использовать сигнал `byte enable`, второй бит которого будет равен `1`. Это значит, что лучше разделить запись в отдельные байты памяти и для каждого байта проверять отдельно соответствующий бит `byte enable`, независимо от остальных. ![../../.pic/Labs/lab_06_main_memory/fig_01.png](../../.pic/Labs/lab_06_main_memory/fig_01.png) -_Рисунок 3. Связь адреса байта с индексом слова в массиве ячеек памяти и сигналом byte enable._ +_Рисунок 1. Связь адреса байта с индексом слова в массиве ячеек памяти и сигналом byte enable._ Чтобы данные остальных байт не были испорчены, при описании памяти на SystemVerilog нужно разделить запись в отдельные байты. Для того, чтобы получить доступ к отдельным диапазонам бит ячейки памяти, после указания индекса ячейки необходимо указать диапазон бит, к которым вы хотите получить доступ. К примеру, чтобы получить доступ к битам с 5-го по 3-ий 18-ой ячейки памяти, необходимо использовать следующую запись: @@ -34,7 +34,7 @@ _Рисунок 3. Связь адреса байта с индексом сло mem[18][5:3]; ``` -Учитывайте и то, что комбинации значений бит в сигнале `byte enable` могут быть любыми: `0000`, `0100`, `0110`, `1111` и т.п. +Учитывайте и то, что комбинации значений бит в сигнале `byte enable` могут быть любыми: `0000`, `0100`, `0110`, `1111` и т.п. ## Задание @@ -97,13 +97,15 @@ import memory_pkg::DATA_MEM_SIZE_WORDS; _Рисунок 2. Операции запросов на чтение._ -Если `mem_req_i == 1` и `write_enable_i == 1`, то происходит запрос на запись в память. В этом случае, необходимо записать значение `write_data_i` в ячейку по, на которую указывает `addr_i`. Во всех других случаях (любой из сигналов `mem_req_i`, `write_enable_i` равен нулю), запись в память не производится. Запись необходимо производить только в те байты указанной ячейки, которым соответствуют биты сигнала `byte_enable_i`, равные единице. +Если `mem_req_i == 1` и `write_enable_i == 1`, то происходит запрос на запись в память. В этом случае, необходимо записать значение `write_data_i` в ячейку по, на которую указывает `addr_i`. Во всех других случаях (любой из сигналов `mem_req_i`, `write_enable_i` равен нулю), запись в память не производится. Запись необходимо производить только в те байты указанной ячейки, которым соответствуют биты сигнала `byte_enable_i`, равные 1. + +На _рис. 3_ показан пример записей по различным адресам. Т.к. деление на 4 любого из приведенных на _рис. 3_ адресов дает результат 2, на рисунке показано только содержимое второй 32-битной ячейки памяти и то, как оно менялось в зависимости от комбинации сигналов `write_data_i` и `byte_enable_i`. ![../../.pic/Labs/lab_06_main_memory/fig_03.wavedrom.svg](../../.pic/Labs/lab_06_main_memory/fig_03.wavedrom.svg) _Рисунок 3. Операции запросов на запись._ -Выход `ready_o` в данном модуле должен всегда быть равен единице, поскольку данные всегда будут выдаваться на следующий такт. В реальности, обращение в память может занимать сотни тактов процессора, причем их число бывает недетерминированным (нельзя заранее предсказать сколько тактов займет очередной запрос в память). Именно поэтому стандартные интерфейсы обычно используют такие сигналы как `ready` или `valid`, позволяющие синхронизировать разные блоки системы. Сигнал `ready_o` в нашем интерфейсе используется сигнала о задержке в выдаче данных. В случае, если устройству нужно больше одного такта, чтобы выдать данные, он устанавливает на данный сигнал значение `0` до тех пор, пока данные не будут готовы. +Выход `ready_o` в данном модуле должен всегда быть равен 1, поскольку данные всегда будут выдаваться на следующий такт. В реальности, обращение в память может занимать сотни тактов процессора, причем их число бывает недетерминированным (нельзя заранее предсказать сколько тактов займет очередной запрос в память). Именно поэтому стандартные интерфейсы обычно используют такие сигналы как `ready` или `valid`, позволяющие синхронизировать разные блоки системы. Сигнал `ready_o` в нашем интерфейсе используется сигнала о задержке в выдаче данных. В случае, если устройству нужно больше одного такта, чтобы выдать данные, он устанавливает на данный сигнал значение `0` до тех пор, пока данные не будут готовы. ## Порядок выполнения работы @@ -121,4 +123,4 @@ _Рисунок 3. Операции запросов на запись._ 1. Тестовое окружение находится [`здесь`](tb_data_mem.sv). 2. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md). 3. Перед запуском симуляции убедитесь, что в качестве top-level модуля выбран корректный (`tb_data_mem`). - 4. **Во время симуляции, вы должны прожать "Run All" и убедиться, что в логе есть сообщение о завершении теста!** + 4. **По завершению симуляции убедитесь, что в логе есть сообщение о завершении теста!**