mirror of
https://github.com/MPSU/APS.git
synced 2025-09-16 01:30:10 +00:00
Переход на использование mem-файлов (#38)
Раньше в вивадо была проблема с использованием mem-файлов. Они нормально моделировались, но при этом не использовались в синтезе, пока им не выставишь тип "Memory Initialization File". Однако с выставлением этого типа файл нельзя было открыть в вивадо (и даже поменять тип этого файла). Поэтому, все файлы в курсе носили расширение .txt, чтобы их можно было легко открыть в любом другом редакторе, а в вивадо выставлялся злополучный тип "Memory Initialization File" вручную. Сейчас же, судя по всему, вивадо нормально выполняет синтез и с "Memory File" тоже, а значит нет нужды в каком-либо изменении типов, лишь бы файлы носили расширение .mem. При этом файлы этого типа можно открывать и редактировать в редакторе вивадо.
This commit is contained in:
committed by
Andrei Solodovnikov
parent
6b2f0c2bab
commit
1bb2fdd323
@@ -153,7 +153,9 @@ module mem16_20 ( // создать блок с именем
|
||||
endmodule
|
||||
```
|
||||
|
||||
В случае реализации ПЗУ нет необходимости в описании входов для записи. В таком случае описание памяти занимает всего пару строк. Чтобы инициализировать такую память (то есть поместить в нее начальные значения, чтобы было что из нее читать), требуемое содержимое нужно добавить к прошивке, вместе с которой данные попадут в ПЛИС. Для этого в проект добавляется текстовый файл с содержимым памяти (более подробно об этом в [`Как добавить файл с содержимым памяти в проект`](../../Vivado%20Basics/How%20to%20add%20a%20mem-file.md)). Для того, чтобы отметить данный файл в качестве инициализирующего память, необходимо использовать одну из двух системных функций: `$readmemh` и `$readmemb`. `$readmemh` используется для файлов, описывающих содержимое памяти 16-ричными цифрами, в то время как `$readmemb` используется для файлов, описывающих содержимое памяти двоичными цифрами. Любую из этих системных функций необходимо поместить внутрь блока `initial`. У этих системных функций есть два обязательных аргумента:
|
||||
В случае реализации ПЗУ нет необходимости в описании входов для записи, поэтому описание памяти занимает всего пару строк. Чтобы проинициализировать такую память (то есть поместить в нее начальные значения, которые можно было бы из нее читать), требуемое содержимое нужно добавить к прошивке, вместе с которой данные попадут в ПЛИС. Для этого в проект добавляется текстовый файл формата `.mem` с содержимым памяти. Для того, чтобы отметить данный файл в качестве инициализирующего память, можно использовать системную функцию `$readmemh`.
|
||||
|
||||
У данной функции есть два обязательных аргумента:
|
||||
|
||||
- имя инициализирующего файла
|
||||
- имя инициализируемой памяти
|
||||
@@ -163,13 +165,13 @@ endmodule
|
||||
- стартовый адрес, начиная с которого память будет проинициализирована данным файлом (по-умолчанию равен нулю)
|
||||
- конечный адрес, на котором инициализация закончится (даже если в файле были ещё какие-то данные).
|
||||
|
||||
Пример полного вызова одной из этих системных функций выглядит так:
|
||||
Пример полного вызова выглядит так:
|
||||
|
||||
`$readmemb("<data file name>",<memory name>,<start address>,<end address>);`
|
||||
`$readmemh("<data file name>",<memory name>,<start address>,<end address>);`
|
||||
|
||||
Однако на деле обычно используются только обязательные аргументы:
|
||||
|
||||
`$readmemb("<data file name>",<memory name>);`
|
||||
`$readmemh("<data file name>",<memory name>);`
|
||||
|
||||
Пример описанной выше памяти:
|
||||
|
||||
@@ -184,8 +186,8 @@ module rom16_8 (
|
||||
logic [7:0] ROM [0:15]; // создать память с 16-ю 8-битными ячейками
|
||||
|
||||
initial begin
|
||||
$readmemh("mem.txt", ROM); // поместить в память RAM содержимое
|
||||
end // файла mem.txt
|
||||
$readmemh("rom_data.mem", ROM); // поместить в память RAM содержимое
|
||||
end // файла rom_data.mem
|
||||
|
||||
|
||||
assign read_data1 = R0M[addr1]; // реализация первого порта на чтение
|
||||
@@ -194,7 +196,7 @@ module rom16_8 (
|
||||
endmodule
|
||||
```
|
||||
|
||||
Содержимое файла `mem.txt`, к примеру может быть таким (каждая строка соответствует значению отдельной ячейки памяти, начиная со стартового адреса):
|
||||
Содержимое файла `rom_data.mem`, к примеру может быть таким (каждая строка соответствует значению отдельной ячейки памяти, начиная со стартового адреса):
|
||||
|
||||
```hex
|
||||
FA
|
||||
@@ -204,6 +206,8 @@ endmodule
|
||||
A7
|
||||
```
|
||||
|
||||
**Для того, чтобы при сборке модуля не было проблем с путями, по которым будет искаться данный файл, обычно его необходимо добавить в проект. В случае Vivado, чтобы тот распознал этот файл как инициализирующий память, необходимо чтобы у этого файла было расширение `.mem`.**
|
||||
|
||||
## Задание по реализации памяти
|
||||
|
||||
Необходимо описать на языке SystemVerilog три вида памяти:
|
||||
@@ -307,7 +311,7 @@ mоdulе rf_r𝚒sсv(
|
||||
1. В `Design Sources` проекта с предыдущих лаб, создайте `SystemVerilog`-файл `instr_mem.sv`.
|
||||
2. Опишите в нем модуль памяти инструкций с таким же именем и портами, как указано в задании.
|
||||
1. Сперва необходимо создать память (массив регистров). Как это сделать, сказано в разделе [описание памяти на языке SystemVerilog](#описание-памяти-на-языке-systemverilog). Разрядность ячеек памяти должна быть 32 бита, количество ячеек — 1024.
|
||||
2. Добавить в проект [`файл с содержимым памяти инструкций`](program.txt)([`как добавить файл, инициализирующий память`](../../Vivado%20Basics/How%20to%20add%20a%20mem-file.md)). Данный файл будет использоваться при вызове системной функции `$readmemh` в описании памяти инструкций.
|
||||
2. Добавить в проект [`файл с содержимым памяти инструкций`](program.mem). Данный файл будет использоваться при вызове системной функции `$readmemh` в описании памяти инструкций.
|
||||
3. К созданной памяти необходимо подключить выход модуля `read_data_o`. При подключении должен быть использован вход модуля `addr_i`, значение которого должно быть уменьшено в 4 раза (побайтовая адресация).
|
||||
4. При реализации выхода `read_data_o` помните, что обращаясь к ячейке памяти, вам необходимо использовать `[11:2]` биты адреса.
|
||||
3. После описания памяти инструкций, её необходимо проверить с помощью тестового окружения.
|
||||
|
@@ -60,7 +60,7 @@ module instr_mem_ref(
|
||||
`define asdasdhkjasdsa (34 >> `cdyfguvhbjnmk)
|
||||
|
||||
reg [31:0] RAM [0:1023];
|
||||
initial $readmemh("program.txt", RAM);
|
||||
initial $readmemh("program.mem", RAM);
|
||||
|
||||
always_comb begin
|
||||
read_data_o['h1f:'h1c]=RAM[{2'b00, addr_i[5'd28^5'o27:2]}][{5{1'b1}}:{3'd7,2'b00}];
|
||||
|
@@ -293,7 +293,7 @@
|
||||
|
||||
Разработать процессор `CYBERcobra`, объединив ранее разработанные модули:
|
||||
|
||||
- Память инструкций (проинициализированную в двоичном формате файлом [`example.txt`](example.txt))
|
||||
- Память инструкций (проинициализированную в двоичном формате файлом [`example.mem`](example.mem))
|
||||
- Регистровый файл
|
||||
- Арифметико-логическое устройство
|
||||
- 32-битный сумматор
|
||||
@@ -331,13 +331,13 @@ endmodule
|
||||
5. Мультиплексор, выбирающий источник записи в регистровый файл.
|
||||
3. После описания модуля, его необходимо проверить с помощью [`тестового окружения`](../../Basic%20Verilog%20structures/Testbench.md).
|
||||
1. Тестовое окружение находится [`здесь`](tb_cybercobra.sv).
|
||||
2. Программа, которой необходимо проинициализировать память инструкций находится [`здесь`](example.txt). Алгоритм работы программы приведен в разделе [`Финальный обзор`](#финальный-обзор).
|
||||
2. Программа, которой необходимо проинициализировать память инструкций находится [`здесь`](example.mem). Алгоритм работы программы приведен в разделе [`Финальный обзор`](#финальный-обзор).
|
||||
3. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
|
||||
4. Перед запуском симуляции убедитесь, что выбран правильный модуль верхнего уровня.
|
||||
5. **Во время симуляции, вы должны прожать "Run All" и убедиться, что в логе есть сообщение о завершении теста!**
|
||||
6. В этот раз, в конце не будет сообщения о том, работает ли ваше устройство или в нем есть ошибки. Вы должны самостоятельно проверить работу модуля, перенеся его внутренние сигналы на временную диаграмму, и [проверив](../../Vivado%20Basics/Debug%20manual.md) логику их работы.
|
||||
4. Добавьте в проект модуль верхнего уровня ([nexys_cybercobra_demo.sv](board%20files/nexys_cybercobra_demo.sv)), соединяющий процессор с периферией в ПЛИС. Описание работы модуля находится [здесь](board%20files)
|
||||
5. Замените содержимое файла, инициализирующего память инструкций новой программой, которая размещена [`здесь`](board%20files/demo.txt).
|
||||
5. Замените содержимое файла, инициализирующего память инструкций новой программой, которая размещена [`здесь`](board%20files/demo.mem).
|
||||
6. Убедитесь, что у файла, инициализирующего память инструкций выставлен тип `Memory Initialization Files`, а не `Memory File`.
|
||||
7. Подключите к проекту файл ограничений ([nexys_a7_100t.xdc](board%20files/nexys_a7_100t.xdc)), если тот еще не был подключен, либо замените его содержимое данными из файла к этой лабораторной работе.
|
||||
8. Проверьте работу процессора в ПЛИС.
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
Если вы не понимаете, что лежит в этой папке, или если надо вспомнить, как прошить ПЛИС, можно воспользоваться [`этой инструкцией`](../../../Vivado%20Basics/Program%20nexys%20a7.md)
|
||||
|
||||
Файл [`nexys_cybercobra_demo.sv`](nexys_cybercobra_demo.sv), который нужно запускать с [`демонстрационным файлом инструкций`](demo.txt), является демонстрацией возможностей кобры, реализующий лишь декодирование выходных значений в формат для отображения на семисегментных индикаторах, а вся логика работы реализована инструкциями в текстовом файле.
|
||||
Файл [`nexys_cybercobra_demo.sv`](nexys_cybercobra_demo.sv), который нужно запускать с [`демонстрационным файлом инструкций`](demo.mem), является демонстрацией возможностей кобры, реализующий лишь декодирование выходных значений в формат для отображения на семисегментных индикаторах, а вся логика работы реализована инструкциями в текстовом файле.
|
||||
|
||||
Сначала выводится приветствие `≡ALOHA≡`, меняя положение восьми правых переключателей, последовательно нажимая на кнопку `BTND` (на рисунке выделена синим цветом), можно включать или выключать `один` из выбранных сегментов. Кнопка `CPU RESET` (на рисунке выделена красным цветом) возвращает все исходное состояние. Попробуйте погасить все слово, а потом снова его зажечь.
|
||||
|
||||
|
@@ -154,10 +154,10 @@ cyberconverter принимает до двух аргументов. Поряд
|
||||
cyberconverter --help
|
||||
```
|
||||
|
||||
2. Преобразование программы, записанной в файле `test.txt`, с записью результата в файл `program.txt`:
|
||||
2. Преобразование программы, записанной в файле `test.txt`, с записью результата в файл `program.mem`:
|
||||
|
||||
```bash
|
||||
cyberconverter test.txt program.txt
|
||||
cyberconverter test.txt program.mem
|
||||
```
|
||||
|
||||
3. Если не указан второй аргумент, результат будет записан в файл:
|
||||
@@ -169,7 +169,7 @@ cyberconverter принимает до двух аргументов. Поряд
|
||||
|
||||
Результат будет записан в файл `test_converted.txt`.
|
||||
|
||||
4. Если программа будет запущена без аргументов, то исходным файлом будет считаться файл `program.txt`.
|
||||
4. Если программа будет запущена без аргументов, то исходным файлом будет считаться файл `program.mem`.
|
||||
|
||||
В случае отсутствия исходного файла, наличия неподдерживаемых символов или неверной длины инструкции будет выведено сообщение об ошибке.
|
||||
|
||||
|
@@ -15,11 +15,11 @@ void print_help(const std::string program_name)
|
||||
cout << "in hex-format.\n\n";
|
||||
cout << "If output file omitted, the <input_file_base>_converted.<input_file_ext>\n";
|
||||
cout << "will be produced.\n\n";
|
||||
cout << "If input file omitted, program.txt will be used.\n\n";
|
||||
cout << "If input file omitted, program.mem will be used.\n\n";
|
||||
cout << "Example:\n\n";
|
||||
cout << program_name << " open \"program.txt\" and produce \"program_converted.txt\"\n";
|
||||
cout << program_name << " open \"program.mem\" and produce \"program_converted.mem\"\n";
|
||||
cout << program_name << " test.txt open \"test.txt\" and produce \"test_converted.txt\"\n";
|
||||
cout << program_name << " test.txt myname.dat open \"test.txt\" and produce \"myname.dat\"\n";
|
||||
cout << program_name << " test.txt myname.mem open \"test.txt\" and produce \"myname.mem\"\n";
|
||||
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ int main(int argc, char ** argv)
|
||||
switch (argc)
|
||||
{
|
||||
case 1:
|
||||
ifname = "program.txt";
|
||||
ofname = "program_converted.txt";
|
||||
ifname = "program.mem";
|
||||
ofname = "program_converted.mem";
|
||||
break;
|
||||
case 2:
|
||||
if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
|
||||
|
@@ -2,4 +2,4 @@
|
||||
|
||||
Если вы не понимаете, что лежит в этой папке, или если надо вспомнить, как прошить ПЛИС, можно воспользоваться [`этой инструкцией`](../../../Vivado%20Basics/Program%20nexys%20a7.md)
|
||||
|
||||
Файл [`nexys_riscv_unit.sv`](nexys_riscv_unit.sv), который нужно запускать с [`демонстрационным файлом инструкций`](../program.txt), является демонстрацией работы вашего ядра, каждое нажатие на BTND формирует тактовый импульс, впоследствии пошагово переходя по инструкциям, которые в свою очередь отображаются на семисегментных индикаторах.
|
||||
Файл [`nexys_riscv_unit.sv`](nexys_riscv_unit.sv), который нужно запускать с [`демонстрационным файлом инструкций`](../program.mem), является демонстрацией работы вашего ядра, каждое нажатие на BTND формирует тактовый импульс, впоследствии пошагово переходя по инструкциям, которые в свою очередь отображаются на семисегментных индикаторах.
|
||||
|
@@ -21,4 +21,4 @@
|
||||
1. Обратите внимание, что что в модуле `riscv_core` появились новые входные и выходные сигналы: `irq_req_i` и `irq_ret_o`. Эти сигналы должны быть использованы при подключении `riscv_core` в модуле `riscv_unit`.
|
||||
1. Ко входу `irq_req_i` должен быть подключен провод `irq_req`, другой конец которого пока не будет ни к чему подключен (в следующей лабораторной это будет изменено).
|
||||
2. К выходу `irq_ret_o` необходимо подключить провод `irq_ret`, который также пока не будет использован.
|
||||
2. После интеграции модулей, проверьте процессорную систему с помощью [программы](irq_program.txt), текст которой [был представлен](../10.%20Interrupt%20subsystem#пример-обработки-перехвата) в ЛР10 с помощью предоставленного [тестбенча](tb_irq_unit.sv).
|
||||
2. После интеграции модулей, проверьте процессорную систему с помощью [программы](irq_program.mem), текст которой [был представлен](../10.%20Interrupt%20subsystem#пример-обработки-перехвата) в ЛР10 с помощью предоставленного [тестбенча](tb_irq_unit.sv).
|
||||
|
@@ -9,7 +9,7 @@ module instr_mem(
|
||||
`define asdasdhkjasdsa (34 >> `cdyfguvhbjnmk)
|
||||
|
||||
reg [31:0] RAM [0:1023];
|
||||
initial $readmemh("program.txt", RAM);
|
||||
initial $readmemh("program.mem", RAM);
|
||||
|
||||
always_comb begin
|
||||
read_data_o['h1f:'h1c]=RAM[{2'b00, addr_i[5'd28^5'o27:2]}][{5{1'b1}}:{3'd7,2'b00}];
|
||||
|
Reference in New Issue
Block a user