mirror of
https://github.com/MPSU/APS.git
synced 2025-09-16 09:40:10 +00:00
WIP: APS cumulative update (#98)
* WIP: APS cumulative update * Update How FPGA works.md * Перенос раздела "Последовательностная логика" в отдельный док * Исправление картинки * Исправление оформления индексов * Переработка раздела Vivado Basics * Добавление картинки в руководство по созданию проекта * Исправление ссылок в анализе rtl * Обновление изображения в sequential logic * Исправление ссылок в bug hunting * Исправление ссылок * Рефактор руководства по прошивке ПЛИС * Mass update * Update fig_10 * Restore fig_02
This commit is contained in:
committed by
GitHub
parent
78bb01ef95
commit
a28002e681
@@ -1,4 +1,4 @@
|
||||
# Лабораторная работа 15 "Программатор"
|
||||
# Лабораторная работа №15 "Программатор"
|
||||
|
||||
Чтобы выпустить микроконтроллер в "дикую природу", то есть, чтобы его можно было использовать не в лабораторных условиях, а независимо от всего этого дополнительного оборудования, необходимо предусмотреть механизм замены исполняемой программы.
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
Опишем данный автомат в виде графа переходов:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 1. Граф переходов конечного автомата для турникета[[1]](https://en.wikipedia.org/wiki/Finite-state_machine)._
|
||||
|
||||
@@ -62,17 +62,17 @@ _Рисунок 1. Граф переходов конечного автомат
|
||||
|
||||
Как мы видим, повторное опускание жетона в разблокированном состоянии приводит к сохранению этого состояния (но турникет не запоминает, что было опущено 2 жетона, и после первого же прохода станет заблокирован). В случае попытки поворота треноги в заблокированном состоянии, автомат так и останется в заблокированном состоянии.
|
||||
|
||||
Так же необходимо оговорить приоритет переходов: в первую очередь проверяется попытка поворота треноги, в случае если такой попытки не было, проверяется опускание монетки. Такой приоритет можно было бы указать и на графе, показав на ребрах что переход в состояние unlocked возможен только при отсутствии сигнала `push`.
|
||||
Так же необходимо оговорить приоритет переходов: в первую очередь проверяется попытка поворота треноги, в случае если такой попытки не было, проверяется опускание монетки. Такой приоритет можно было бы указать и на графе, показав на рёбрах что переход в состояние unlocked возможен только при отсутствии сигнала `push`.
|
||||
|
||||
### Реализация конечных автоматов в SystemVerilog
|
||||
|
||||
Глядя на описание составляющих конечного автомата, вы могли задаться вопросом: чем автомат отличается от последовательностной логики, ведь она состоит из тех же компонент. Ответом будет: ничем. Конечные автоматы являются математической абстракцией над функцией последовательностной логики[[3]](https://www.allaboutcircuits.com/textbook/digital/chpt-11/finite-state-machines/). Иными словами — конечный автомат, это просто другой способ представления последовательностной логики, а значит вы уже умеете их реализовывать.
|
||||
Глядя на описание составляющих конечного автомата, вы могли задаться вопросом: чем автомат отличается от последовательностной логики, ведь она состоит из тех же компонент. Ответом будет: ничем. Конечные автоматы являются математической абстракцией над функцией последовательностной логики[[2]](https://www.allaboutcircuits.com/textbook/digital/chpt-11/finite-state-machines/). Иными словами — конечный автомат, это просто другой способ представления последовательностной логики, а значит вы уже умеете их реализовывать.
|
||||
|
||||
Для реализации регистра состояния конечного автомата будет удобно воспользоваться специальным типом языка **SystemVerilog**, который называется `enum` (**перечисление**).
|
||||
|
||||
Перечисления позволяют объявить объединенный набор именованных констант. В дальнейшем, объявленные имена можно использовать вместо перечисленных значений, им соответствующих, что повышает читаемость кода. Если не указано иного, первому имени присваивается значение `0`, каждое последующее увеличивается на `1` относительно предыдущего значения.
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module turnstile_fsm(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
@@ -81,26 +81,27 @@ module turnstile_fsm(
|
||||
output logic is_locked
|
||||
)
|
||||
|
||||
enum logic {LOCKED=1, UNLOCKED=0} state;
|
||||
enum logic {LOCKED=1, UNLOCKED=0} state;
|
||||
|
||||
assign is_locked = state == LOCKED;
|
||||
assign is_locked = state == LOCKED;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if(rst) begin
|
||||
always_ff @(posedge clk) begin
|
||||
if(rst) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
else begin
|
||||
if(push) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
else if (coin) begin
|
||||
state <= UNLOCKED;
|
||||
end
|
||||
else begin
|
||||
if(push) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
else if (coin) begin
|
||||
state <= UNLOCKED;
|
||||
end
|
||||
else begin
|
||||
state <= state;
|
||||
end
|
||||
state <= state;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 1. Пример реализации конечного автомата для турникета._
|
||||
@@ -111,9 +112,9 @@ _Листинг 1. Пример реализации конечного авто
|
||||
|
||||
_Рисунок 2. Вывод значений объекта `enum` на временную диаграмму._
|
||||
|
||||
Для описания регистра состояния часто используют отдельный комбинационный сигнал, который подается непосредственно на его вход (часто именуемый как `next_state`). Приведенный выше автомат турникета слишком простой, чтобы показать преимущества такого подхода. Предположим, что в момент перехода из состояния `locked` в состояние `unlocked` мы хотим, чтобы загоралась и сразу гасла зеленая лампочка. Без сигнала `next_state` подобный модуль можно было бы описать как:
|
||||
Для описания регистра состояния часто используют отдельный комбинационный сигнал, который подаётся непосредственно на его вход (часто именуемый как `next_state`). Приведённый выше автомат турникета слишком простой, чтобы показать преимущества такого подхода. Предположим, что в момент перехода из состояния `locked` в состояние `unlocked` мы хотим, чтобы загоралась и сразу гасла зелёная лампочка. Без сигнала `next_state` подобный модуль можно было бы описать как:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module turnstile_fsm(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
@@ -123,36 +124,37 @@ module turnstile_fsm(
|
||||
output logic green_light
|
||||
)
|
||||
|
||||
enum logic {LOCKED=1, UNLOCKED=0} state;
|
||||
enum logic {LOCKED=1, UNLOCKED=0} state;
|
||||
|
||||
assign is_locked = ststate == LOCKED;
|
||||
assign is_locked = ststate == LOCKED;
|
||||
|
||||
// (!push) && coin — условие перехода в состояние UNLOCKED
|
||||
assign green_light = (state == LOCKED) && (!push) && coin;
|
||||
// (!push) && coin — условие перехода в состояние UNLOCKED
|
||||
assign green_light = (state == LOCKED) && (!push) && coin;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if(rst) begin
|
||||
always_ff @(posedge clk) begin
|
||||
if(rst) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
else begin
|
||||
if(push) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
else if (coin) begin
|
||||
state <= UNLOCKED;
|
||||
end
|
||||
else begin
|
||||
if(push) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
else if (coin) begin
|
||||
state <= UNLOCKED;
|
||||
end
|
||||
else begin
|
||||
state <= state;
|
||||
end
|
||||
state <= state;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 2. Пример реализации конечного автомата для усложненного турникета._
|
||||
_Листинг 2. Пример реализации конечного автомата для усложнённого турникета._
|
||||
|
||||
Используя сигнал `next_state`, автомат мог бы быть переписан следующим образом:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module turnstile_fsm(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
@@ -162,37 +164,38 @@ module turnstile_fsm(
|
||||
output logic green_light
|
||||
)
|
||||
|
||||
enum logic {LOCKED=1, UNLOCKED=0} state, next_state;
|
||||
enum logic {LOCKED=1, UNLOCKED=0} state, next_state;
|
||||
|
||||
assign is_locked = state;
|
||||
assign is_locked = state;
|
||||
|
||||
assign green_light = (state == LOCKED) && (next_state == UNLOCKED);
|
||||
assign green_light = (state == LOCKED) && (next_state == UNLOCKED);
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if(rst) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
else begin
|
||||
state <= next_state
|
||||
end
|
||||
always_ff @(posedge clk) begin
|
||||
if(rst) begin
|
||||
state <= LOCKED;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
if(push) begin
|
||||
next_state = LOCKED;
|
||||
end
|
||||
else if (coin) begin
|
||||
next_state = UNLOCKED;
|
||||
end
|
||||
else begin
|
||||
next_state = state;
|
||||
end
|
||||
else begin
|
||||
state <= next_state
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
if(push) begin
|
||||
next_state = LOCKED;
|
||||
end
|
||||
else if (coin) begin
|
||||
next_state = UNLOCKED;
|
||||
end
|
||||
else begin
|
||||
next_state = state;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 3. Пример реализации конечного автомата для усложненного турникета с использованием сигнала next\_state._
|
||||
_Листинг 3. Пример реализации конечного автомата для усложнённого турникета с использованием сигнала next\_state._
|
||||
|
||||
На первый взгляд может показаться, что так даже сложнее. Во-первых, появился дополнительный сигнал. Во-вторых, появился еще один `always`-блок. Однако представьте на секунду, что условиями перехода будут не однобитные входные сигналы, а какие-нибудь более сложные условия. И что от них будет зависеть не один выходной сигнал, а множество как выходных сигналов, так и внутренних элементов памяти помимо регистра состояний. В этом случае, сигнал `next_state` позволит избежать дублирования множества условий.
|
||||
На первый взгляд может показаться, что так даже сложнее. Во-первых, появился дополнительный сигнал. Во-вторых, появился ещё один `always`-блок. Однако представьте на секунду, что условиями перехода будут не однобитные входные сигналы, а какие-нибудь более сложные условия. И что от них будет зависеть не один выходной сигнал, а множество как выходных сигналов, так и внутренних элементов памяти помимо регистра состояний. В этом случае, сигнал `next_state` позволит избежать дублирования множества условий.
|
||||
|
||||
Важно отметить, что объектам типа `enum` можно присваивать только перечисленные константы и объекты того же типа. Иными словами, `state` можно присваивать значения `LOCKED`/`UNLOCKED` и `next_state`, но нельзя, к примеру, присвоить `1'b0`.
|
||||
|
||||
@@ -206,9 +209,9 @@ _Листинг 3. Пример реализации конечного авто
|
||||
|
||||
### Перезаписываемая память инструкций
|
||||
|
||||
Поскольку ранее из памяти инструкций можно было только считывать данные, но не записывать их в нее, программатор не сможет записать принятую из внешнего мира программу. Поэтому необходимо добавить в память инструкций порт на запись. Для того, чтобы различать реализации памяти инструкций, данный модуль будет называться `rw_instr_mem`:
|
||||
Поскольку ранее из памяти инструкций можно было только считывать данные, но не записывать их в неё, программатор не сможет записать принятую из внешнего мира программу. Поэтому необходимо добавить в память инструкций порт на запись. Для того, чтобы различать реализации памяти инструкций, данный модуль будет называться `rw_instr_mem`:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module rw_instr_mem
|
||||
import memory_pkg::INSTR_MEM_SIZE_BYTES;
|
||||
import memory_pkg::INSTR_MEM_SIZE_WORDS;
|
||||
@@ -269,7 +272,7 @@ _Рисунок 3. Граф перехода между состояниями
|
||||
|
||||
Ниже представлен прототип модуля с частично реализованной логикой:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module bluster
|
||||
(
|
||||
input logic clk_i,
|
||||
@@ -393,7 +396,6 @@ uart_tx tx(
|
||||
.tx_valid_i (tx_valid )
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
@@ -441,21 +443,21 @@ _Листинг 5. Готовая часть программатора._
|
||||
|
||||
Для работы логики переходов, необходимо реализовать счетчики `size_counter`, `flash_counter`, `msg_counter`.
|
||||
|
||||
`size_counter` должен сбрасываться в значение `4`, а также принимать это значение во всех состояниях кроме: `RCV_SIZE`, `RCV_NEXT_COMMAND`. В данных двух состояниях счетчик должен декрементироваться в случае, если `rx_valid` равен единице.
|
||||
`size_counter` должен сбрасываться в значение `4`, а также принимать это значение во всех состояниях кроме: `RCV_SIZE`, `RCV_NEXT_COMMAND`. В данных двух состояниях счётчик должен декрементироваться в случае, если `rx_valid` равен единице.
|
||||
|
||||
`flash_counter` должен сбрасываться в значение `flash_size`, а также принимать это значение во всех состояниях кроме `FLASH`. В этом состоянии счетчик должен декрементироваться в случае, если `rx_valid` равен единице.
|
||||
`flash_counter` должен сбрасываться в значение `flash_size`, а также принимать это значение во всех состояниях кроме `FLASH`. В этом состоянии счётчик должен декрементироваться в случае, если `rx_valid` равен единице.
|
||||
|
||||
`msg_counter` должен сбрасываться в значение `INIT_MSG_SIZE-1` (в _Листинге 5_ объявлены параметры `INIT_MSG_SIZE`, `FLASH_MSG_SIZE` и `ACK_MSG_SIZE`).
|
||||
|
||||
Счетчик должен инициализироваться следующим образом:
|
||||
счётчик должен инициализироваться следующим образом:
|
||||
|
||||
- в состоянии `FLASH` счетчик должен принимать значение `FLASH_MSG_SIZE-1`,
|
||||
- в состоянии `RCV_SIZE` счетчик должен принимать значение `ACK_MSG_SIZE-1`,
|
||||
- в состоянии `RCV_NEXT_COMMAND` счетчик должен принимать значение `INIT_MSG_SIZE-1`.
|
||||
- в состоянии `FLASH` счётчик должен принимать значение `FLASH_MSG_SIZE-1`,
|
||||
- в состоянии `RCV_SIZE` счётчик должен принимать значение `ACK_MSG_SIZE-1`,
|
||||
- в состоянии `RCV_NEXT_COMMAND` счётчик должен принимать значение `INIT_MSG_SIZE-1`.
|
||||
|
||||
В состояниях: `INIT_MSG`, `SIZE_ACK`, `FLASH_ACK` счетчик должен декрементироваться в случае, если `tx_valid` равен единице.
|
||||
В состояниях: `INIT_MSG`, `SIZE_ACK`, `FLASH_ACK` счётчик должен декрементироваться в случае, если `tx_valid` равен единице.
|
||||
|
||||
Во всех остальных ситуациях счетчик должен сохранять свое значение.
|
||||
Во всех остальных ситуациях счётчик должен сохранять свое значение.
|
||||
|
||||
##### Реализация сигналов, подключаемых к uart_tx
|
||||
|
||||
@@ -469,11 +471,11 @@ _Листинг 5. Готовая часть программатора._
|
||||
|
||||
Сигнал `tx_data` должен нести очередной байт одного из передаваемых сообщений:
|
||||
|
||||
- в состоянии `INIT_MSG` передается очередной байт сообщения `init_msg`
|
||||
- в состоянии `SIZE_ACK` передается очередной байт сообщения `flash_size`
|
||||
- в состоянии `FLASH_ACK` передается очередной байт сообщения `flash_msg`.
|
||||
- в состоянии `INIT_MSG` передаётся очередной байт сообщения `init_msg`
|
||||
- в состоянии `SIZE_ACK` передаётся очередной байт сообщения `flash_size`
|
||||
- в состоянии `FLASH_ACK` передаётся очередной байт сообщения `flash_msg`.
|
||||
|
||||
В остальных состояниях он равен нулю. Для отсчета байт используется счетчик `msg_counter`.
|
||||
В остальных состояниях он равен нулю. Для отсчёта байт используется счётчик `msg_counter`.
|
||||
|
||||
##### Реализация интерфейсов памяти инструкций и данных
|
||||
|
||||
@@ -531,7 +533,7 @@ _Рисунок 4. Интеграция программатора в `riscv_uni
|
||||
|
||||
Необходимо подключить отладочный стенд к последовательному порту компьютера (в случае платы Nexys A7 — достаточно просто подключить плату usb-кабелем, как это делалось на протяжении всех лабораторных для прошивки). Необходимо будет узнать COM-порт, по которому отладочный стенд подключен к компьютеру. Определить нужный COM-порт на операционной системе Windows можно через "Диспетчер устройств", который можно открыть через меню пуск. В данном окне необходимо найти вкладку "Порты (COM и LPT)", раскрыть ее, а затем подключить отладочный стенд через USB-порт (если тот еще не был подключен). В списке появится новое устройство, а в скобках будет указан нужный COM-порт.
|
||||
|
||||
Подключив отладочный стенд к последовательному порту компьютера и сконфигурировав ПЛИС вашим проектом остается проинициализировать память. Сделать это можно с помощью предоставленного скрипта, пример запуска которого приведен в листинге 6.
|
||||
Подключив отладочный стенд к последовательному порту компьютера и сконфигурировав ПЛИС вашим проектом, остается проинициализировать память. Сделать это можно с помощью предоставленного скрипта, пример запуска которого приведен в листинге 6.
|
||||
|
||||
```bash
|
||||
# Пример использования скрипта. Сперва указываются опциональные аргументы
|
||||
@@ -563,35 +565,28 @@ _Листинг 6. Пример использования скрипта для
|
||||
## Порядок выполнения задания
|
||||
|
||||
1. Опишите модуль `rw_instr_mem`, используя код, представленный в _листинге 4_.
|
||||
2. Добавьте пакет [`bluster_pkg`](bluster_pkg.sv), содержащий объявления параметров, используемых модулем и вспомогательных вызовов, используемых тестбенчем.
|
||||
2. Добавьте пакет [`bluster_pkg`](bluster_pkg.sv), содержащий объявления параметров и вспомогательных вызовов, используемых модулем и тестбенчем.
|
||||
3. Опишите модуль `bluster`, используя код, представленный в _листинге 5_. Завершите описание этого модуля.
|
||||
1. Опишите конечный автомат используя сигналы `state`, `next_state`, `send_fin`, `size_fin`, `flash_fin`, `next_round`.
|
||||
2. [Реализуйте](#реализация-конечного-автомата) логику счетчиков `size_counter`, `flash_counter`, `msg_counter`.
|
||||
3. [Реализуйте](#реализация-сигналов-подключаемых-к-uart_tx) логику сигналов `tx_valid`, `tx_data`.
|
||||
4. [Реализуйте](#реализация-интерфейсов-памяти-инструкций-и-данных) интерфейсы памяти инструкций и данных.
|
||||
5. [Реализуйте](#реализация-оставшейся-части-логики) логику оставшихся сигналов.
|
||||
4. После описания модуля, его необходимо проверить с помощью тестового окружения.
|
||||
1. Тестбенч находится [здесь](lab_15_tb_bluster.sv).
|
||||
2. Для работы тестбенча потребуется потребуется пакет [`peripheral_pkg`](../13.%20Peripheral%20units/peripheral_pkg.sv) из ЛР№13, а также файлы [`lab_15_char.mem`](lab_15_char.mem), [`lab_15_data.mem`](lab_15_data.mem), [`lab_15_instr.mem`](lab_15_instr.mem) из папки [mem_files](mem_files).
|
||||
3. Перед запуском симуляции убедитесь, что в качестве top-level модуля выбран корректный (`lab_15_tb_bluster`).
|
||||
4. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
|
||||
5. **По завершению симуляции убедитесь, что в логе есть сообщение о завершении теста!**
|
||||
5. Интегрируйте программатор в модуль `riscv_unit`.
|
||||
1. Замените память инструкцией модулем `rw_instr_mem`.
|
||||
2. Добавьте модуль программатор.
|
||||
3. Подключите программатор к процессорной системе.
|
||||
4. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_15.tb_bluster.sv`](lab_15.tb_bluster.sv). В случае, если в TCL-консоли появились сообщения об ошибках, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) и исправить их.
|
||||
1. Перед запуском моделирования, убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
||||
2. Для работы тестбенча потребуется пакет [`peripheral_pkg`](../13.%20Peripheral%20units/peripheral_pkg.sv) из ЛР№13, а также файлы [`lab_15_char.mem`](lab_15_char.mem), [`lab_15_data.mem`](lab_15_data.mem), [`lab_15_instr.mem`](lab_15_instr.mem) из папки [mem_files](mem_files).
|
||||
5. Интегрируйте программатор в модуль `processor_system`.
|
||||
1. В модуле `processor_system` замените память инструкцией модулем `rw_instr_mem`.
|
||||
2. Добавьте в модуль `processor_system` экземпляр модуля-программатора.
|
||||
1. Интерфейс памяти инструкций подключается к порту записи модуля `rw_instr_mem`.
|
||||
2. Интерфейс памяти данных мультиплексируется с интерфейсом памяти данных модуля `LSU`.
|
||||
3. Замените сигнал сброса модуля `riscv_core` сигналом `core_reset_o`.
|
||||
4. В случае если у вас есть периферийное устройство `uart_tx` его выход `tx_o` необходимо мультиплексировать с выходом `tx_o` программатора аналогично тому, как был мультиплексирован интерфейс памяти данных.
|
||||
6. После интеграции модуля, его необходимо проверить с помощью тестового окружения.
|
||||
1. Тестовое окружение находится [здесь](lab_15_tb_system.sv).
|
||||
1. Данный тестбенч необходимо обновить под свой вариант. Найдите строки со вспомогательным вызовом `program_region`, первыми аргументами которого являются "YOUR_INSTR_MEM_FILE" и "YOUR_DATA_MEM_FILE". Обновите эти строки под имена файлов, которыми вы инициализировали свои память инструкций и данных в ЛР№13. Если память данных вы не инициализировали, можете удалить/закомментировать соответствующий вызов. При необходимости вы можете добавить столько вызовов, сколько вам потребуется.
|
||||
2. В .mem-файлах, которыми вы будете инициализировать вашу память необходимо сделать доработку. Вам необходимо указать адрес ячейки памяти, с которой необходимо начать инициализировать память. Это делается путем добавления в начало файла строки вида: `@hex_address`. Пример `@FA000000`. Строка обязательно должна начинаться с символа `@`, а адрес обязательно должен быть в шестнадцатеричном виде. Для памяти инструкций нужен нулевой адрес, а значит можно использовать строку `@00000000`. Для памяти данных необходимо адрес, превышающий размер памяти инструкций, но не попадающий в адресное пространство других периферийных устройств (старший байт адреса должен быть равен нулю). Поскольку система использует байтовую адресацию, адрес ячеек будет в 4 раза меньше адреса по которому обратился бы процессор. Это значит, что если бы вы хотели проинициализировать память VGA-контроллера, вам нужно было бы использовать не адрес `@07000000`, а `@01C00000` (`01C00000 * 4 = 07000000`). Таким образом, для памяти данных оптимальным адресом инициализации будет `@00200000`, поскольку эта ячейка с адресом `00200000` соответствует адресу `00800000` — этот адрес не накладывается на адресное пространство других периферийных устройств, но при этом заведомо больше возможного размера памяти инструкций. Примеры использования начальных адресов вы можете посмотреть в файлах [`lab_15_char.mem`](lab_15_char.mem), [`lab_15_data.mem`](lab_15_data.mem), [`lab_15_instr.mem`](lab_15_instr.mem) из папки [mem_files](mem_files).
|
||||
3. Тестбенч будет ожидать завершения инициализации памяти, после чего сформирует те же тестовые воздействия, что и в тестбенче к ЛР№13. А значит, если вы использовали для инициализации те же самые файлы, поведение вашей системы после инициализации не должно отличаться от поведения на симуляции в ЛР№13.
|
||||
2. Перед запуском симуляции убедитесь, что в качестве top-level модуля выбран корректный (`lab_15_tb_system`).
|
||||
3. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
|
||||
4. **По завершению симуляции убедитесь, что в логе есть сообщение о завершении теста!**
|
||||
6. Проверьте процессорную систему после интеграции программатора с помощью верификационного окружения, представленного в файле [`lab_15.tb_processor_system.sv`](lab_15.tb_processor_system.sv).
|
||||
1. Данный тестбенч необходимо обновить под свой вариант. Найдите строки со вспомогательным вызовом `program_region`, первыми аргументами которого являются "YOUR_INSTR_MEM_FILE" и "YOUR_DATA_MEM_FILE". Обновите эти строки под имена файлов, которыми вы инициализировали свои память инструкций и данных в ЛР№13. Если память данных вы не инициализировали, можете удалить/закомментировать соответствующий вызов. При необходимости вы можете добавить столько вызовов, сколько вам потребуется.
|
||||
2. В .mem-файлах, которыми вы будете инициализировать вашу память необходимо сделать доработку. Вам необходимо указать адрес ячейки памяти, с которой необходимо начать инициализировать память. Это делается путем добавления в начало файла строки вида: `@hex_address`. Пример `@FA000000`. Строка обязательно должна начинаться с символа `@`, а адрес обязательно должен быть в шестнадцатеричном виде. Для памяти инструкций нужен нулевой адрес, а значит можно использовать строку `@00000000`. Для памяти данных необходимо адрес, превышающий размер памяти инструкций, но не попадающий в адресное пространство других периферийных устройств (старший байт адреса должен быть равен нулю). Поскольку система использует байтовую адресацию, адрес ячеек будет в 4 раза меньше адреса по которому обратился бы процессор. Это значит, что если бы вы хотели проинициализировать память VGA-контроллера, вам нужно было бы использовать не адрес `@07000000`, а `@01C00000` (`01C00000 * 4 = 07000000`). Таким образом, для памяти данных оптимальным адресом инициализации будет `@00200000`, поскольку эта ячейка с адресом `00200000` соответствует адресу `00800000` — этот адрес не накладывается на адресное пространство других периферийных устройств, но при этом заведомо больше возможного размера памяти инструкций. Примеры использования начальных адресов вы можете посмотреть в файлах [`lab_15_char.mem`](lab_15_char.mem), [`lab_15_data.mem`](lab_15_data.mem), [`lab_15_instr.mem`](lab_15_instr.mem) из папки [mem_files](mem_files).
|
||||
3. Тестбенч будет ожидать завершения инициализации памяти, после чего сформирует те же тестовые воздействия, что и в тестбенче к ЛР№13. А значит, если вы использовали для инициализации те же самые файлы, поведение вашей системы после инициализации не должно отличаться от поведения на симуляции в ЛР№13.
|
||||
4. Перед запуском моделирования, убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
||||
7. Переходить к следующему пункту можно только после того, как вы полностью убедились в работоспособности системы на этапе моделирования (увидели, что в память инструкций и данных были записаны корректные данные, после чего процессор стал обрабатывать прерывания от устройства ввода). Генерация битстрима будет занимать у вас долгое время, а итогом вы получите результат: заработало / не заработало, без какой-либо дополнительной информации, поэтому без прочного фундамента на моделировании далеко уехать у вас не выйдет.
|
||||
8. Подключите к проекту файл ограничений ([nexys_a7_100t.xdc](nexys_a7_100t.xdc)), если тот еще не был подключен, либо замените его содержимое данными из файла к этой лабораторной работе.
|
||||
9. Проверьте работу вашей процессорной системы на отладочном стенде с ПЛИС.
|
||||
@@ -603,3 +598,5 @@ _Листинг 6. Пример использования скрипта для
|
||||
## Список источников
|
||||
|
||||
1. [Finite-state machine](https://en.wikipedia.org/wiki/Finite-state_machine).
|
||||
2. [All about circuits — Finite State Machines](https://www.allaboutcircuits.com/textbook/digital/chpt-11/finite-state-machines/)
|
||||
3.
|
||||
|
Reference in New Issue
Block a user