Compare commits

...

14 Commits

Author SHA1 Message Date
Andrei Solodovnikov
4cac36212b Обновление workflows 2026-10-05 15:46:33 +03:00
Andrei Solodovnikov
06da941d8a Update lab_06.data_mem.sv 2026-09-16 16:44:51 +03:00
Andrei Solodovnikov
78ff35477b Л15. Исправление иерархического подключения core 2026-09-16 16:38:55 +03:00
Andrei Solodovnikov
e5d28642a7 Л15. Переименование тб 2026-09-16 16:36:28 +03:00
Andrei Solodovnikov
5e5a4cf4ab ЛР1. Уточнение формулировки 2026-09-16 15:32:02 +03:00
Andrei Solodovnikov
4c70d10f17 Исправление ссылки на fpga-systems
Closes #166
2026-08-10 13:10:47 +03:00
Andrei Solodovnikov
2e39ba5542 ЛР16. Обновление tb_coremark 2026-07-30 12:05:21 +03:00
Andrei Solodovnikov
df1c6a3d41 ЛР13. Дополнение ps2ascii_data.mem
Дополнительно инициализируется 60-ое слово памяти (адрес 0xf0), чтобы на моделировании не было чтений неопределенного значения.
2026-07-29 13:48:07 +03:00
Andrei Solodovnikov
4676bf3b77 ЛР10-11. Обновление листинга 2026-07-25 16:41:01 +03:00
Andrei Solodovnikov
a64da6312b ЛР12. Исправление вывода в тб
В утверждении irq_cause_o_mcause при ошибке выводилось значение не из тех бит.

Fixes #165
2026-07-24 00:16:07 +03:00
Andrei Solodovnikov
bfb6bac9d5 ЛР8. Исправление тб
Из-за гонок не отлавливалась ошибка когда core_stall_o брался с выхода регистра
2026-07-22 14:52:47 +03:00
Andrei Solodovnikov
4aa7ed1be8 Исправление отображения svg (#164) 2026-07-01 14:33:40 +03:00
Andrei Solodovnikov
4313c22bee ЛР5. Стилистические правки 2026-07-01 14:29:23 +03:00
Andrei Solodovnikov
007889f849 ЛР4. Обновление тестбенча
Замена reg и wire, исправление нейминга сигналов, способов установки
задержек, а также уменьшен интервал вводимых чисел для уменьшения длины
временной диаграммы.
2026-07-01 14:29:23 +03:00
19 changed files with 253 additions and 1242 deletions

View File

@@ -1,4 +1,4 @@
# Builds the Russian (master) and English (english_version) editions of the
# Builds the Russian and English editions of the
# mdBook and deploys them as one GitHub Pages site:
#
# /APS/ ← Russian
@@ -8,7 +8,7 @@ name: Deploy mdBook site to Pages
on:
push:
branches: ["master", "english_version"]
branches: ["russian_version", "english_version"]
workflow_dispatch:
permissions:
@@ -27,9 +27,11 @@ jobs:
MDBOOK_VERSION: 0.4.36
steps:
# ── 1. Checkout master (Russian) ──────────────────────────────────────
- name: Checkout master (Russian)
# ── 1. Checkout Russian version ──────────────────────────────────────
- name: Checkout Russian version
uses: actions/checkout@v4
with:
ref: russian_version
# checks out into $GITHUB_WORKSPACE (i.e. the working directory)
# ── 2. Install mdBook ─────────────────────────────────────────────────
@@ -68,7 +70,7 @@ jobs:
# Use the dedicated English book.toml (sets site-url = "/APS/en/")
cp .github/book_en.toml book.toml
# Copy language-switcher theme files from the master checkout
# Copy language-switcher theme files from the russian_version checkout
cp -r ../.github/theme ./theme
- name: Build English (mdbook → english_src/book/)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 127 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 137 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 142 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 41 KiB

116
ERRATA.md
View File

@@ -2,6 +2,122 @@
![http://95.215.8.74:5000/days_since_last_commit.png](http://95.215.8.74:5000/days_since_last_commit.png)
**25.07.2026**: В _листинг II.10-1_ (стр. 179-181) были внесены изменения:
1. Адреса программного стека и стека прерываний изменены с `3FFC` и `1FFC` на `1F0` и `F0` соответственно.
Младшая часть адресов изменена с `C` на `0` поскольку верхушка стека должна быть выровнена по границе в 16 байт (таково требование соглашения о вызовах).
Старшая часть адреса была уменьшена с `3F` до `01` и с `1F` до `00`, чтобы оба стека уместились в исходную память данных, чей размер изначально был задан в `memory_pkg` репозитория на значении в 512 байт.
2. Поскольку адреса `1F0` и `F0` умещаются в 12 бит, загрузка этих адресов теперь умещается в одну инструкцию, а не две. Благодаря этому, инструкции `li`, расположенные по адресам `0x00` и `0x18` разворачиваются в одну инструкцию `addi`. Из-за этого изменились адреса всех инструкций в листинге.
3. В листинге была допущена ошибка: верхушка указателя на стек была записана в регистр `x2`, однако в последствии в качестве верхушки стека использовался регистр `x5`. Теперь листинг использует корректный регистр `x2`.
4. В начале обработчика перехвата `trap_handler` между инструкциями с адресами `0x44` и `0x48` была пропущена инструкция поднятия верхушки стека на 16 байт вверх `addi x2, x2, -16`. Аналогично, была пропущена инструкция опускания верхушки стека на 16 байт вниз `addi x2, x2, 16` в конце обработчика `done` между инструкциями с адресами `0x90` и `0x94` соответственно.
<details>
<summary> Исправленная версия листинга </summary>
```asm
_start:
# Инициализируем начальные значения регистров
00: li x2, 0x00001F0 # устанавливаем указатель на верхушку стека
04: li x3, 0x00000000 # устанавливаем указатель на глобальные данные
08: la x5, trap_handler # псевдоинструкция la аналогично li загружает число,
# только в случае la — это число является адресом
# указанного места (адресом обработчика перехвата)
0C: csrw mtvec, x5 # устанавливаем вектор прерывания
10: li x5, 0x000000F0 # готовим адрес верхушки стека прерывания
14: csrw mscratch, x5 # загружаем указатель на верхушку стека прерывания
18: li x5, -1 # подготавливаем маску, разрешающую все источники
# прерывания
1C: csrw mie, x5 # загружаем маску в регистр маски
20: li x5, 1 # начальное значение глобальной переменной
24: sw x5, 0(x3) # загружаем переменную в память
28: li x6, 0 # начальное значение, чтобы в симуляции не было xxx
2C: li x7, 0 # начальное значение, чтобы в симуляции не было xxx
# Вызов ecall исключительно из хулиганских соображений, поскольку в данной
# микроархитектурной реализации это приведет к появлению illegal_instr и
# последующей обработке исключения
30: ecall
# Вызов функции main
main:
34: beq x0, x0, main # бесконечный цикл, аналогичный while (1);
# ОБРАБОТЧИК ПЕРЕХВАТА
# Без стороннего вмешательства процессор никогда не перейдёт к инструкциям ниже,
# однако в случае перехвата в программный счетчик будет загружен адрес первой
# нижележащей инструкции.
# Сохраняем используемые регистры на стек
trap_handler:
38: csrrw x2, mscratch, x2 # меняем местами mscratch и x2
3C: addi x2, x2, -16 # поднимаем верхушку стека на 16 байт вверх
# (указатель на стек всегда должен быть выровнен
# по границе в 16 байт)
40: sw x6, 0(x2) # сохраняем x6 на стек mscratch
44: sw x7, 4(x2) # сохраняем x7 на стек mscratch
# Проверяем произошло ли прерывание
48: csrr x6, mcause # x6 = mcause
4C: li x7, 0x80000010 # загружаем в x7 код того, что произошло прерывание
50: # данная псевдоинструкция будет разбита на две
# инструкции: lui и addi
54: bne x6, x7, exc_handler # если коды не совпадают, переходим к проверке
# на исключение
# Обработчик прерывания
58: lw x7, 0(x3) # загружаем переменную из памяти
5C: addi x7, x7, 3 # прибавляем к значению 3
60: sw x7, 0(x3) # возвращаем переменную в память
64: j done # идем возвращать регистры и на выход
exc_handler: # Проверяем произошло ли исключение
68: li x7, 0x0000002 # загружаем в x7 код того, что произошло исключение
6C: bne x6, x7, done # если это не оно, то выходим
# Обработчик исключения
70: csrr x6, mepc # Узнаём значение PC (адреса инструкции,
# вызвавшей исключение)
74: lw x7, 0x0(x6) # Загружаем эту инструкцию в регистр x7.
# В текущей микроархитектурной реализации это
# невозможно, т.к. память инструкций отделена от
# памяти данных и не участвует в выполнении
# операций load / store.
# Другой способ узнать об инструкции, приведшей
# к исключению — добавить поддержку статусного
# регистра mtval, в который при исключении
# может быть записана текущая инструкция.
# Теоретически мы могли бы после этого
# сделать что-то, в зависимости от этой инструкции.
# Например, если это операция умножения — вызвать
# подпрограмму умножения.
78: addi x6, x6, 4 # Увеличиваем значение PC на 4, чтобы после
# возврата не попасть на инструкцию, вызвавшую
# исключение.
7C: csrw mepc, x6 # Записываем обновленное значение PC в регистр mepc
80: j done # идем восстанавливать регистры со стека и на выход
# Возвращаем регистры на места и выходим
done:
84: lw x6, 0(x2) # возвращаем x6 со стека
88: lw x7, 4(x2) # возвращаем x7 со стека
8C: addi x2, x2, 16 # опускаем верхушку стека обратно на 16 байт вниз
90: csrrw x2, mscratch, x2 # меняем обратно местами x2 и mscratch
94: mret # возвращаем управление программе (pc = mepc)
# что означает возврат в бесконечный цикл
```
</details>
<br>
**30.12.2025**: В Финальном обзоре ЛР№4 (стр. 111) указан неверный тип константы для инструкций переходов: 23-битная `const`, в то время как на самом деле используется 8-битная `offset`.
<details>

View File

@@ -139,7 +139,7 @@ _Рисунок 3. Цифровая схема модуля half_adder, сген
Подаваемые на схему входные воздействия формируются верификационным окружением. Верификационное окружение (в дальнейшем будет использован термин "**тестбенч**") — это особый несинтезируемый модуль, который не имеет входных или выходных сигналов. Эти сигналы ему не нужны, потому что он сам является генератором всех своих внутренних сигналов, и данный модуль не передаёт ничего вовне — только проверяет тестируемый модуль внутри себя.
Внутри тестбенча можно использовать конструкции из несинтезируемого подмножества языка SystemVerilog, в частности программный блок `initial`, в котором команды выполняются последовательно, что делает этот блок чем-то отдалённо похожим на проверяющую программу. Поскольку изменение внутренних цепей происходит с некоторой задержкой относительно изменений входных сигналов, при моделировании есть возможность делать паузы между командами. Это делается с помощью специального символа #, за которым указывается количество времени симуляции, которое нужно пропустить перед следующей командой.
Внутри тестбенча можно использовать конструкции из несинтезируемого подмножества языка SystemVerilog, в частности программный блок `initial`, в котором команды выполняются последовательно, что делает этот блок чем-то отдалённо похожим на проверяющую программу. Чтобы разнести подаваемые на схему тестовые воздействия по времени, при моделировании есть возможность делать паузы между командами. Это делается с помощью специального символа #, за которым указывается количество времени симуляции, которое нужно пропустить перед следующей командой.
Перед тем как писать верификационное окружение, необходимо составить план того, как будет проводиться проверка устройства (составить верификационный план). Ввиду предельной простоты устройства, план будет состоять из одного предложения:

View File

@@ -10,33 +10,40 @@ See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
*/
module lab_04_tb_CYBERcobra();
CYBERcobra DUT(
logic [31:0] OUT;
logic clk;
logic rst;
logic [15:0] sw_i;
CYBERcobra DUT(
.clk_i(clk),
.rst_i(rstn),
.sw_i (sw_i ),
.rst_i(rst),
.sw_i (sw_i),
.out_o(OUT)
);
);
wire [31:0] OUT;
reg clk;
reg rstn;
reg [15:0] sw_i;
initial clk <= 0;
always #5ns clk = ~clk;
initial clk <= 0;
always #5 clk = ~clk;
initial begin
initial begin
logic [15:0] count_num;
$display("Test has been started");
rstn = 1'b1;
#10;
rstn = 1'b0;
sw_i = 16'b100001000; //значение, до которого считает счетчик
#10000;
$display("\n The test is over \n See the internal signals of the CYBERcobra on the waveform \n");
$finish;
#5;
$display("You're trying to run simulation that has finished. Aborting simulation.");
$fatal();
rst = 1'b1;
repeat(2)@(posedge clk);
rst = 1'b0;
count_num = $urandom_range(5, 10);
sw_i = count_num;
repeat(count_num * 2 + 15) begin
@(posedge clk);
end
$display("\nThe test is over.");
$display("See the internal signals of the CYBERcobra on the waveform");
$finish;
@(posedge clk);
$display("You're trying to run simulation that has finished.");
$display("Aborting simulation.");
$fatal();
end
endmodule

View File

@@ -338,7 +338,7 @@ _Таблица 7. Описание портов дешифратора кома
## Инструменты
**SystemVerilog** – это язык описания аппаратуры. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору – как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него нужно. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы хорошо знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также – одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. Однако, часто два разных кода, одинаковых по смыслу, могут синтезироваться в разную аппаратуру, хотя функционально они будут идентичны, но могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
**SystemVerilog** – это язык описания аппаратуры. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору – как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него требуется. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы хорошо знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также – одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. В то же время два одинаковых по смыслу кода могут синтезироваться в разную аппаратуру. Будучи функционально идентичными, они могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
Декодер – комбинационная схема. Это значит, что каждый раз подавая на вход одни и те же значения, вы будете получать на выходе один и тот же результат.

View File

@@ -83,7 +83,7 @@ initial begin
$stop();
not_stopped = 0;
end
@(posedge clk_i);
@(negedge clk_i);
if(!core_stall_o) begin
core_req_i = $random;
core_we_i = $random;

View File

@@ -237,81 +237,74 @@ _Рисунок 5. Структурная схема контроллера пр
```asm
_start:
# Инициализируем начальные значения регистров
00: li x2, 0x00003FF0 # устанавливаем указатель на верхушку стека
04: # данная псевдоинструкция будет разбита на две
# инструкции: lui и addi
00: li x2, 0x00001F0 # устанавливаем указатель на верхушку стека
04: li x3, 0x00000000 # устанавливаем указатель на глобальные данные
08: li x3, 0x00000000 # устанавливаем указатель на глобальные данные
0С: la x5, trap_handler # псевдоинструкция la аналогично li загружает число,
10: # только в случае la — это число является адресом
08: la x5, trap_handler # псевдоинструкция la аналогично li загружает число,
# только в случае la — это число является адресом
# указанного места (адресом обработчика перехвата)
# данная псевдоинструкция будет разбита на две
# инструкции: lui и addi
14: csrw mtvec, x5 # устанавливаем вектор прерывания
0C: csrw mtvec, x5 # устанавливаем вектор прерывания
18: li x5, 0x00001FFC # готовим адрес верхушки стека прерывания
1С: # данная псевдоинструкция будет разбита на две
# инструкции: lui и addi
10: li x5, 0x000000F0 # готовим адрес верхушки стека прерывания
20: csrw mscratch, x5 # загружаем указатель на верхушку стека прерывания
14: csrw mscratch, x5 # загружаем указатель на верхушку стека прерывания
24: li x5, 0x00010000 # подготавливаем маску прерывания единственного
# входа прерываний
18: li x5, -1 # подготавливаем маску, разрешающую все источники
# прерывания
28: csrw mie, x5 # загружаем маску в регистр маски
1C: csrw mie, x5 # загружаем маску в регистр маски
2С: li x5, 1 # начальное значение глобальной переменной
30: sw x5, 0(x3) # загружаем переменную в память
20: li x5, 1 # начальное значение глобальной переменной
24: sw x5, 0(x3) # загружаем переменную в память
34: li x6, 0 # начальное значение, чтобы в симуляции не было xxx
38: li x7, 0 # начальное значение, чтобы в симуляции не было xxx
28: li x6, 0 # начальное значение, чтобы в симуляции не было xxx
2C: li x7, 0 # начальное значение, чтобы в симуляции не было xxx
# Вызов ecall исключительно из хулиганских соображений, поскольку в данной
# микроархитектурной реализации это приведет к появлению illegal_instr и
# последующей обработке исключения
3С: ecall
30: ecall
# Вызов функции main
main:
40: beq x0, x0, main # бесконечный цикл, аналогичный while (1);
34: beq x0, x0, main # бесконечный цикл, аналогичный while (1);
# ОБРАБОТЧИК ПЕРЕХВАТА
# Без стороннего вмешательства процессор никогда не перейдет к инструкциям ниже,
# Без стороннего вмешательства процессор никогда не перейдёт к инструкциям ниже,
# однако в случае перехвата в программный счетчик будет загружен адрес первой
# нижележащей инструкции.
# Сохраняем используемые регистры на стек
trap_handler:
44: csrrw x5, mscratch, x5 # меняем местами mscratch и x5
48: addi x5, x5, -16 # поднимаем верхушку стека на 16 байт вверх
38: csrrw x2, mscratch, x2 # меняем местами mscratch и x2
3C: addi x2, x2, -16 # поднимаем верхушку стека на 16 байт вверх
# (указатель на стек всегда должен быть выровнен
# границе в 16 байт)
4С: sw x6, 0(x5) # сохраняем x6 на стек mscratch
50: sw x7, 4(x5) # сохраняем x7 на стек mscratch
# по границе в 16 байт)
40: sw x6, 0(x2) # сохраняем x6 на стек mscratch
44: sw x7, 4(x2) # сохраняем x7 на стек mscratch
# Проверяем произошло ли прерывание
54: csrr x6, mcause # x6 = mcause
58: li x7, 0x80000010 # загружаем в x7 код того, что произошло прерывание
5С: # данная псевдоинструкция будет разбита на две
48: csrr x6, mcause # x6 = mcause
4C: li x7, 0x80000010 # загружаем в x7 код того, что произошло прерывание
50: # данная псевдоинструкция будет разбита на две
# инструкции: lui и addi
60: bne x6, x7, exc_handler # если коды не совпадают, переходим к проверке
54: bne x6, x7, exc_handler # если коды не совпадают, переходим к проверке
# на исключение
# Обработчик прерывания
64: lw x7, 0(x3) # загружаем переменную из памяти
68: addi x7, x7, 3 # прибавляем к значению 3
6С: sw x7, 0(x3) # возвращаем переменную в память
70: j done # идем возвращать регистры и на выход
58: lw x7, 0(x3) # загружаем переменную из памяти
5C: addi x7, x7, 3 # прибавляем к значению 3
60: sw x7, 0(x3) # возвращаем переменную в память
64: j done # идем возвращать регистры и на выход
exc_handler: # Проверяем произошло ли исключение
74: li x7, 0x0000002 # загружаем в x7 код того, что произошло исключение
78: bne x6, x7, done # если это не оно, то выходим
68: li x7, 0x0000002 # загружаем в x7 код того, что произошло исключение
6C: bne x6, x7, done # если это не оно, то выходим
# Обработчик исключения
7С: csrr x6, mepc # Узнаём значение PC (адреса инструкции,
70: csrr x6, mepc # Узнаём значение PC (адреса инструкции,
# вызвавшей исключение)
80: lw x7, 0x0(x6) # Загружаем эту инструкцию в регистр x7.
74: lw x7, 0x0(x6) # Загружаем эту инструкцию в регистр x7.
# В текущей микроархитектурной реализации это
# невозможно, т.к. память инструкций отделена от
# памяти данных и не участвует в выполнении
@@ -325,19 +318,19 @@ exc_handler: # Проверяем произошло ли иск
# Например, если это операция умножения — вызвать
# подпрограмму умножения.
84: addi x6, x6, 4 # Увеличиваем значение PC на 4, чтобы после
78: addi x6, x6, 4 # Увеличиваем значение PC на 4, чтобы после
# возврата не попасть на инструкцию, вызвавшую
# исключение.
88: csrw mepc, x6 # Записываем обновленное значение PC в регистр mepc
8С: j done # идем восстанавливать регистры со стека и на выход
7C: csrw mepc, x6 # Записываем обновленное значение PC в регистр mepc
80: j done # идем восстанавливать регистры со стека и на выход
# Возвращаем регистры на места и выходим
done:
90: lw x6, 0(x5) # возвращаем x6 со стека
94: lw x7, 4(x5) # возвращаем x7 со стека
98: addi x5, x5, 16 # опускаем верхушку стека обратно на 16 байт вниз
9С: csrrw x5, mscratch, x5 # меняем обратно местами x5 и mscratch
A0: mret # возвращаем управление программе (pc = mepc)
84: lw x6, 0(x2) # возвращаем x6 со стека
88: lw x7, 4(x2) # возвращаем x7 со стека
8C: addi x2, x2, 16 # опускаем верхушку стека обратно на 16 байт вниз
90: csrrw x2, mscratch, x2 # меняем обратно местами x2 и mscratch
94: mret # возвращаем управление программе (pc = mepc)
# что означает возврат в бесконечный цикл
```

View File

@@ -1,13 +1,10 @@
00004137
FF010113
1f000113
00000193
04400293
00028293
03800293
30529073
000022B7
FFC28293
0F000293
34029073
000102B7
FFF00293
30429073
00100293
0051A023
@@ -15,10 +12,10 @@ FFC28293
00000393
00000073
00000063
340292F3
ff028293
0062A023
0072A223
34011173
FF010113
00612023
00712223
34202373
800003B7
01038393
@@ -34,8 +31,8 @@ ff028293
00430313
34131073
0040006F
0002A303
0042A383
01028293
340292F3
00012303
00412383
01010113
34011173
30200073

View File

@@ -82,11 +82,11 @@ irq_o_is_not_0: assert property (
irq_cause_o_mcause: assert property (
@(posedge clk_i) disable iff ( rst_i )
irq_o |-> $onehot0(irq_cause_o[19:4])
)else $error("error value on irq_cause_o: %08h, should be onehot", $sampled(irq_cause_o[20:5]));
)else $error("error value on irq_cause_o: %08h, should be onehot", $sampled(irq_cause_o[19:4]));
irq_cause_o_borders: assert property (
@(posedge clk_i) disable iff ( rst_i )
irq_o |-> (irq_cause_o[31:20] === 12'h800) && (irq_cause_o[3:0] == 4'h0)
)else $error("irq_cause_o borders are incorrect: %08h", $sampled(irq_cause_o));
endmodule
endmodule

View File

@@ -1,3 +1,4 @@
@00000000
00000000
00000000
00000000
@@ -21,3 +22,5 @@
00270000
00003D5B
5D0D0000
@00000060
00000000

View File

@@ -8,7 +8,7 @@
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module lab_15_tb_system();
module lab_15_tb_processor_system();
logic clk_i;
logic sysclk;
@@ -111,7 +111,7 @@ module lab_15_tb_system();
.sw_i (sw_i )
);
assign core_reset = DUT.core_inst.rst_i;
assign core_reset = DUT.core.rst_i;
uart_rx rx(
.clk_i (sysclk ),

View File

@@ -9,16 +9,16 @@ See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module lab_16_tb_coremark();
import bluster_pkg::*;
logic clk100mhz_i;
logic aresetn_i;
logic rx_i;
logic tx_o;
logic clk_i;
logic rst_i;
logic core_reset;
assign aresetn_i = !rst_i;
assign core_reset = DUT.core.rst_i;
logic rx_busy, rx_valid, tx_busy, tx_valid;
logic [7:0] rx_data, tx_data;
@@ -38,7 +38,7 @@ module lab_16_tb_coremark();
repeat(2) @(posedge clk_i);
rst_i <= 0;
dummy_programming();
finish_programming(clk_i, tx_valid, tx_busy, core_reset, tx_data);
coremark_cntr = 0;
coremark_msg = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
@@ -90,59 +90,4 @@ uart_tx tx(
.tx_valid_i (tx_valid )
);
task send_data(input byte mem[$]);
for(int i = mem.size()-1; i >=0; i--) begin
tx_data = mem[i];
tx_valid = 1'b1;
@(posedge clk_i);
tx_valid = 1'b0;
@(posedge clk_i);
while(tx_busy) @(posedge clk_i);
end
endtask
task rcv_data(input int size);
byte str[57];
logic [3:0][7:0] size_val;
for(int i = 0; i < size; i++) begin
@(posedge clk_i);
while(!rx_valid)@(posedge clk_i);
str[i] = rx_data;
size_val[3-i] = rx_data;
end
if(size!=4)$display("%s", str);
else $display("%d", size_val);
wait(tx_o);
endtask
task program_region(input byte mem[$], input logic [3:0][7:0] start_addr);
byte str [4];
logic [3:0][7:0] size;
size = mem.size();
if(start_addr) begin
str = {start_addr[0],start_addr[1],start_addr[2],start_addr[3]};
send_data(str);
end
rcv_data(40);
str = {size[0],size[1],size[2],size[3]};
send_data(str);
rcv_data(4);
send_data(mem);
rcv_data(57);
endtask
task finish_programming();
send_data({8'd0, 8'd0, 8'd0, 8'd0});
endtask
task dummy_programming();
byte str [4] = {8'd0, 8'd0, 8'd0, 8'd0};
rcv_data(40);
send_data(str);
rcv_data(4);
rcv_data(57);
send_data(str);
endtask
endmodule

View File

@@ -8,8 +8,7 @@
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module data_mem(
module data_mem (
input logic clk_i,
input logic mem_req_i,
input logic write_enable_i,
@@ -23,78 +22,22 @@ assign ready_o = 1'b1;
import memory_pkg::DATA_MEM_SIZE_WORDS;
logic [31:0] ram [DATA_MEM_SIZE_WORDS];
logic [31:0] addr;
assign addr = addr_i[2+:$clog2(DATA_MEM_SIZE_WORDS)];
always_ff @(posedge clk_i) begin
case(1)
!mem_req_i||write_enable_i: read_data_o <= read_data_o;
default: read_data_o <= ram[addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]];
endcase
if(mem_req_i & !write_enable_i) begin
read_data_o <= ram[addr];
end
end
always_ff @(posedge clk_i) begin
case({mem_req_i, write_enable_i, byte_enable_i})
6'd49: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
if(mem_req_i & write_enable_i) begin
if(byte_enable_i[0]) ram[addr][ 7: 0] = write_data_i[ 7: 0];
if(byte_enable_i[1]) ram[addr][15: 8] = write_data_i[15: 8];
if(byte_enable_i[2]) ram[addr][23:16] = write_data_i[23:16];
if(byte_enable_i[3]) ram[addr][31:24] = write_data_i[31:24];
end
6'd50: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
end
6'd51: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
end
6'd52: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
end
6'd53: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
end
6'd54: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
end
6'd55: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
end
6'd56: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
6'd57: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
6'd58: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
6'd59: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
6'd60: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
6'd61: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
6'd62: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
6'd63: begin
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [7:0] <= write_data_i[7:0];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [15:8] <= write_data_i[15:8];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [23:16] <= write_data_i[23:16];
ram [addr_i[32'ha&32'h2+:$clog2(DATA_MEM_SIZE_WORDS)]] [31:24] <= write_data_i[31:24];
end
endcase
end
endmodule

View File

@@ -8,7 +8,7 @@
## Про программируемые логические интегральные схемы (ПЛИС) и Verilog
- [fpga-systems.ru](https://fpga-systems.ru) – FPGA-Systems – это не только интернет-ресурс с различными статьями о ПЛИС, но и живое, постоянно обновляемое и растущее сообщество разработчиков, которое организует тематические конференции, а участники обмениваются вопросами/ответами в коллективных чатах, ссылки на которые можно найти на сайте. В российском сегменте интернета очень полезный ресурс для тех, кто хочет развивать навыки разработчика под ПЛИС
- [fpga-systems.org](https://fpga-systems.org) – FPGA-Systems – это не только интернет-ресурс с различными статьями о ПЛИС, но и живое, постоянно обновляемое и растущее сообщество разработчиков, которое организует тематические конференции, а участники обмениваются вопросами/ответами в коллективных чатах, ссылки на которые можно найти на сайте. В российском сегменте интернета очень полезный ресурс для тех, кто хочет развивать навыки разработчика под ПЛИС
- [FPGA-Awesome-List](https://github.com/FPGA-Systems/fpga-awesome-list) – Список полезных ресурсов связанных с темой ПЛИС от сообщества FPGA-Systems, тут много полезной информации
- [opencores.org](https://opencores.org/projects) – Сайт, на котором собраны открытые (бесплатные, то есть скачать можно) IP-блоки самых разных цифровых устройств, написанные на разных языках описания аппаратуры, например, в разделе "Processors" можно найти процессоры с самыми различными архитектурами, скачать их, прошить, посмотреть, потрогать, поэкспериментировать. Процессоры с RISC-V там тоже, конечно же, есть. Не все IP-блоки написаны на Verilog
- [Problem sets Verilog syntax](https://hdlbits.01xz.net/wiki/Problem_sets) – Крутой самоучитель по Verilog, но на английском. Все очень удобно разбито по темам, рассчитано на самого начинающего. Даже Vivado запускать не надо, можно вбивать и проверять код прямо на сайте, пушка!