Compare commits

..

40 Commits

Author SHA1 Message Date
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
Andrei Solodovnikov
e09e48adff ЛР16. Исправление мейкфайла
Мейкфайл был написан из рассчета что startup.S будет в barebones,
но в методичке сказано скопировать его в корень кормарка.
2026-06-24 21:09:00 +03:00
Andrei Solodovnikov
8ffbc7a01b ЛР15. Исправление разрядности sw_i в тб 2026-06-18 13:17:12 +03:00
Andrei Solodovnikov
da422cfccb Исправление имени модуля в примере FAQ
Fix the instantiation of the adder module in the testbench.
2026-05-19 14:17:31 +03:00
Andrei Solodovnikov
71cb2f3099 Исправление имени модуля в примере common mistakes 2026-05-19 13:41:13 +03:00
Andrei Solodovnikov
63260f434e ЛР10. Исправление рисунка
Линии немного "съехали", функциональных изменений нет.
2026-05-07 15:59:11 +03:00
Andrei Solodovnikov
1034565000 WIP: сборка английской версии mdbook 2026-05-07 13:47:55 +03:00
ProshinaNastya
ccf769f48f ЛР5,7,9. Стилистические правки (#157)
* ЛР4. Удаление дублирования

* незначительные исправления README.md

* ЛР7. Исправление незначительных ошибок

* ЛР 9. Исправление пунктуации

* Apply suggestions from code review

Co-authored-by: Andrei Solodovnikov <VoultBoy@yandex.ru>

---------

Co-authored-by: Andrei Solodovnikov <VoultBoy@yandex.ru>
2026-04-25 10:39:17 +03:00
ProshinaNastya
44910a0b57 ЛР4. Удаление дублирования (#156) 2026-04-18 11:54:25 +03:00
Andrei Solodovnikov
a424d5c40f ЛР7. Исправление описки 2026-04-16 16:18:00 +03:00
Andrei Solodovnikov
896f7fccda ЛР10. Унификация заголовка 2026-04-14 09:46:01 +03:00
Andrei Solodovnikov
40074bcb25 ЛР2. Унификация заголовка 2026-04-14 09:45:33 +03:00
Andrei Solodovnikov
b480505e11 Исправление опечаток в документе "What is HDL" 2026-04-12 15:38:09 +03:00
Andrei Solodovnikov
59b569a1e4 Уточнение формулировки в документе "Как работает ПЛИС" 2026-04-12 14:13:08 +03:00
Andrei Solodovnikov
7ebed1ded9 ЛР15. Исправление имени модуля DUT в тб 2026-04-08 12:38:56 +03:00
Andrei Solodovnikov
0b9d7fb3bc Переименование списка вопросов к экзамену для группы КТ 2026-04-06 12:46:38 +03:00
Andrei Solodovnikov
145b19dccb ЛР15. Исправление имени модуля в тб 2026-04-03 15:29:29 +03:00
Andrei Solodovnikov
3871c41cda Обновление презентаций лекций 2026-03-31 11:16:25 +03:00
Andrei Solodovnikov
c9fa090383 ЛР3. Ссылка на спецификацию в описании нулевого регистра 2026-03-16 16:20:03 +03:00
Andrei Solodovnikov
581ef9ff48 Обновлениее описания Цифровой схемотехники 2026-03-11 14:17:37 +03:00
Andrei Solodovnikov
097863cf65 ЛР16. Исправление ссылки 2026-03-03 14:20:56 +03:00
Andrei Solodovnikov
a78e4a8ab0 Удаление ссылки на вики из документа по мультиплексорам. 2026-03-03 14:05:40 +03:00
Andrei Solodovnikov
0168dc0d65 ЛР16. Добавление ссылки на интеграцию Coremark 2026-03-03 14:04:38 +03:00
Andrei Solodovnikov
eaa9c22f08 Обновление определения мультиплексора 2026-03-02 17:37:39 +03:00
Andrei Solodovnikov
5f62e9d318 Обновление презентаций лекций 2026-03-02 14:29:48 +03:00
Andrei Solodovnikov
af916e9068 ЛР16. Исправление опечатки 2026-02-27 13:13:56 +03:00
Andrei Solodovnikov
cc39a87aaf Обновление ip студ-сервера на иллюстрациях 2026-02-10 15:39:40 +03:00
Andrei Solodovnikov
97903627ac Update README.md 2026-01-14 16:09:22 +03:00
Andrei Solodovnikov
e6879fec59 ЛР10. Улучшение формулировки 2026-01-12 16:53:56 +03:00
Andrei Solodovnikov
0bc66d1e1f ЛР4. Исправление описания итогового формата инструкций (#155)
В инструкциях переходов была ошибочно указана const вместо offset
2025-12-30 16:40:30 +03:00
irinamokeeva510-creator
e16fd228e6 ЛР1-3, 5, 10. Исправление орфографии и формулировок (#154)
* Update README.md

исправлены две ошибки 
1)Ошибки:«увосьмиренной разрядности»
Лучше: «увосьмеренной разрядности» 
2)«Подробней»
Нормативно: «Подробнее».

* Update README.md

1) «…производить над входными данным…»
Правильно: «…производить над входными данными…» (Т.п., мн.ч.)
2) грамматика в формулировках условий таблиц:
«не входящим в эту таблицу» лучше: «не входящем» (о коде операции в ед. числе) (в двух строках одна и та же ошибка)

* Update README.md

logic [19:0] memory3 [15:0];  // объявлено
logic [19:0] memory3 [1:16];  // объявлено ещё
Имя memory3 используется дважды — это синтаксическая ошибка в реальном коде,второе объявление должно быть memory4 или другим именем.

* Унификация слова "подробнее".

* Ёфикация

* ЛР2. Уточнение формулировки

---------

Co-authored-by: Andrei Solodovnikov <voultboy@yandex.ru>
2025-12-22 11:18:55 +03:00
Andrei Solodovnikov
fa5bb16bbd ЛР2. Добавление направленного теста для EQ/NE 2025-12-12 09:15:09 +03:00
Andrei Solodovnikov
d903badf3c ЛР11. Исправление проверки на случай неподключенного сигнала 2025-12-02 10:44:01 +03:00
Andrei Solodovnikov
d72f6b424f ЛР10. Добавление остановки после 10 ошибок в tb_irq 2025-11-28 09:24:14 +03:00
Andrei Solodovnikov
0604def3cf ЛР10. Исправление формата вывода в tb_irq 2025-11-28 09:10:06 +03:00
43 changed files with 595 additions and 2137 deletions

2
.github/Intro.md vendored
View File

@@ -151,7 +151,7 @@ Readme.md
Здесь находятся методические материалы ко всем 16 лабораторным работам, разложенные по соответствующим им папкам.
Практически в каждой такой папке находится файл формата _lab_xx.tb_xxx.sv_ — это файл с верификационным окружением для данной лабораторной работы. Такой файл необходимо добавлять в _Simulation Sources_ проекта (подробней в разделе _Vivado Basics_).
Практически в каждой такой папке находится файл формата _lab_xx.tb_xxx.sv_ — это файл с верификационным окружением для данной лабораторной работы. Такой файл необходимо добавлять в _Simulation Sources_ проекта (подробнее в разделе _Vivado Basics_).
Кроме того, в папке лабораторной работы могут находиться _xxx_pkg.sv_ и _xxx.mem_ файлы, содержащие соответственно параметры и данные, которыми необходимо проинициализировать память устройства. Такие файлы будет необходимо добавлять в _Design Sources_ проекта.

4
.github/book.toml vendored
View File

@@ -1,10 +1,12 @@
[book]
authors = ["Andrei Solodovnikov, Mikhail Popov"]
language = "ru"
multilingual = true
src = "./"
title = "Архитектуры процессорных систем"
[output.html]
git-repository-url = "https://github.com/MPSU/APS"
git-repository-icon = "fa-github"
site-url = "/APS/"
additional-js = ["theme/language-switcher.js"]
additional-css = ["theme/language-switcher.css"]

12
.github/book_en.toml vendored Normal file
View File

@@ -0,0 +1,12 @@
[book]
authors = ["Andrei Solodovnikov, Mikhail Popov"]
language = "en"
src = "./"
title = "Processor System Architectures"
[output.html]
git-repository-url = "https://github.com/MPSU/APS"
git-repository-icon = "fa-github"
site-url = "/APS/en/"
additional-js = ["theme/language-switcher.js"]
additional-css = ["theme/language-switcher.css"]

8
.github/prepare.sh vendored
View File

@@ -1,4 +1,10 @@
#!/bin/bash
set -e
mkdir src
mkdir -p src
cp .github/book.toml .github/*.md ./
# Copy custom theme assets (language switcher, etc.)
if [ -d ".github/theme" ]; then
cp -r .github/theme ./
fi

44
.github/theme/language-switcher.css vendored Normal file
View File

@@ -0,0 +1,44 @@
/* ── Language Switcher ───────────────────────────────────────────────────── */
#language-switcher {
display: inline-flex;
align-items: center;
gap: 4px;
background: none;
border: 1px solid var(--icons);
border-radius: 4px;
color: var(--icons);
cursor: pointer;
font-size: 0.82em;
font-weight: 600;
line-height: 1;
padding: 3px 8px;
/* sit nicely alongside the existing icon buttons */
margin-right: 4px;
vertical-align: middle;
transition: color 0.15s, border-color 0.15s, background 0.15s;
}
#language-switcher:hover,
#language-switcher:focus-visible {
color: var(--icons-hover);
border-color: var(--icons-hover);
background-color: rgba(128, 128, 128, 0.08);
outline: none;
}
/* Keep the flag emoji from being shrunk by the parent flex layout */
#language-switcher span[aria-hidden] {
font-size: 1.1em;
line-height: 1;
}
/* Hide text label on very small screens, show only flag */
@media (max-width: 420px) {
#language-switcher .lang-label {
display: none;
}
}

149
.github/theme/language-switcher.js vendored Normal file
View File

@@ -0,0 +1,149 @@
(function () {
"use strict";
const STORAGE_KEY = "book-language";
// ---------------------------------
// Current language from URL
// ---------------------------------
function currentLang() {
return /\/en\//.test(window.location.pathname) ? "en" : "ru";
}
// ---------------------------------
// Browser language
// ---------------------------------
function preferredLang() {
const langs = navigator.languages || [
navigator.language || "en",
];
const isRussian = langs.some((lang) =>
lang.toLowerCase().startsWith("ru")
);
return isRussian ? "ru" : "en";
}
// ---------------------------------
// URL conversion
// ---------------------------------
function pathForLang(lang) {
const path = window.location.pathname;
if (lang === "en") {
if (/\/en\//.test(path)) {
return path;
}
// /APS/foo → /APS/en/foo
return path.replace(/^(\/[^\/]+\/)/, "$1en/");
}
// lang === "ru"
// /APS/en/foo → /APS/foo
return path.replace("/en/", "/");
}
// ---------------------------------
// Switch language manually
// ---------------------------------
function switchLanguage() {
const newLang = currentLang() === "ru" ? "en" : "ru";
// Save explicit user choice
localStorage.setItem(STORAGE_KEY, newLang);
window.location.href =
pathForLang(newLang) +
window.location.search +
window.location.hash;
}
// ---------------------------------
// Automatic language selection
// ---------------------------------
function autoSelectLanguage() {
const current = currentLang();
// 1. User preference has priority
let desired = localStorage.getItem(STORAGE_KEY);
// 2. Otherwise use browser language
if (!desired) {
desired = preferredLang();
}
// Already correct
if (desired === current) {
return;
}
// Redirect
window.location.replace(
pathForLang(desired) +
window.location.search +
window.location.hash
);
}
// ---------------------------------
// UI
// ---------------------------------
function addSwitcher() {
const lang = currentLang();
const btn = document.createElement("button");
btn.id = "language-switcher";
btn.setAttribute(
"title",
lang === "ru"
? "Switch to English"
: "Переключить на русский"
);
btn.setAttribute("aria-label", btn.getAttribute("title"));
const icon = document.createElement("span");
icon.setAttribute("aria-hidden", "true");
icon.textContent = lang === "ru" ? "🇬🇧" : "🇷🇺";
const label = document.createElement("span");
label.className = "lang-label";
label.textContent = lang === "ru" ? "EN" : "RU";
btn.appendChild(icon);
btn.appendChild(label);
btn.addEventListener("click", switchLanguage);
const target = document.querySelector(".right-buttons");
if (target) {
target.insertBefore(btn, target.firstChild);
}
}
// ---------------------------------
// Init
// ---------------------------------
function init() {
autoSelectLanguage();
addSwitcher();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();

View File

@@ -1,55 +1,98 @@
# Sample workflow for building and deploying a mdBook site to GitHub Pages
# Builds the Russian (master) and English (english_version) editions of the
# mdBook and deploys them as one GitHub Pages site:
#
# To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html
# /APS/ ← Russian
# /APS/en/ ← English
#
name: Deploy mdBook site to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
branches: ["master", "english_version"]
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
env:
MDBOOK_VERSION: 0.4.36
steps:
- uses: actions/checkout@v4
# ── 1. Checkout master (Russian) ──────────────────────────────────────
- name: Checkout master (Russian)
uses: actions/checkout@v4
# checks out into $GITHUB_WORKSPACE (i.e. the working directory)
# ── 2. Install mdBook ─────────────────────────────────────────────────
- name: Install mdBook
run: |
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y
source "$HOME/.cargo/env"
cargo install --version "${MDBOOK_VERSION}" mdbook
# ── 3. Build Russian version ──────────────────────────────────────────
- name: Prepare Russian sources
run: |
chmod +x .github/prepare.sh
.github/prepare.sh
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
rustup update
cargo install --version ${MDBOOK_VERSION} mdbook
- name: Build Russian (mdbook → ./book/)
run: |
source "$HOME/.cargo/env"
mdbook build
# ── 4. Checkout English branch ────────────────────────────────────────
- name: Checkout english_version branch
uses: actions/checkout@v4
with:
ref: english_version
path: english_src # checked out next to the working directory
# ── 5. Build English version ──────────────────────────────────────────
- name: Prepare English sources
run: |
cd english_src
chmod +x .github/prepare.sh
.github/prepare.sh
# 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
cp -r ../.github/theme ./theme
- name: Build English (mdbook → english_src/book/)
run: |
source "$HOME/.cargo/env"
cd english_src
mdbook build
# ── 6. Merge artifacts ────────────────────────────────────────────────
- name: Merge English build into Russian book/en/
run: |
mkdir -p book/en
cp -r english_src/book/. book/en/
# ── 7. Deploy ─────────────────────────────────────────────────────────
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
- name: Build with mdBook
run: mdbook build
- name: Upload artifact
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./book
# Deployment job
deploy:
environment:
name: github-pages

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

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -32,7 +32,7 @@ endmodule
module testbench();
logic A, B, C;
adder DUT(
half_adder DUT(
.A(A), // <- здесь будет ошибка,
// т.к. в модуле half_adder нет порта 'A'
.b(B),

View File

@@ -1,6 +1,6 @@
# Описание мультиплексоров в SystemVerilog
**Мультипле́ксор** — устройство, имеющее **несколько сигнальных входов**, **один или более управляющих входов** и **один выход**. Мультиплексор позволяет передавать сигнал **с одного из входов на выход**; при этом выбор желаемого входа осуществляется подачей соответствующей комбинации управляющих сигналов[[1]](https://ru.wikipedia.org/wiki/Мультиплексор_(электроника)).
**Мультипле́ксор** — устройство, которое выбирает один из нескольких входных сигналов и передает его на единственный выход в зависимости от значения управляющего входа.
Иными словами, мультиплексор — это переключатель (коммутатор), соединяющий выход с одним из множества входов.
@@ -226,7 +226,3 @@ assign one_bit_result = bus1024[select];
Как описать на языке SystemVerilog следующую схему?
![../.pic/Basic%20Verilog%20structures/multiplexors/fig_05.drawio.svg](../.pic/Basic%20Verilog%20structures/multiplexors/fig_05.drawio.svg)
## Список источников
1. [Мультиплексор (электроника)](https://ru.wikipedia.org/wiki/Мультиплексор_(электроника)).

150
ERRATA.md
View File

@@ -2,6 +2,140 @@
![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>
<summary> Исправленная версия абзаца </summary>
```diff
1. 10 вычислительных инструкций 0 0 01 alu_op RA1 RA2 xxxx xxxx WA
2. Инструкция загрузки константы 0 0 00 const WA
3. Инструкция загрузки из внешних устройств 0 0 10 xxx xxxx xxxx xxxx xxxx xxxx WA
---4. Безусловный переход 1 x xx xxx xxxx xxxx xxxx const xxxxx
---5. 6 инструкций условного перехода 0 1 xx alu_op RA1 RA2 const xxxxx
+++4. Безусловный переход 1 x xx xxx xxxx xxxx xxxx offset xxxxx
+++5. 6 инструкций условного перехода 0 1 xx alu_op RA1 RA2 offset xxxxx
```
</details>
<br>
**28.10.2025**: В ЛР№3 (стр. 90) указано неверное количество блоков, необходимое для реализации 1&nbsp;KiB памяти.
<details>
@@ -11,7 +145,7 @@
</details>
<br><br>
<br>
**27.10.2025**: Исправлено отображение инверсии выхода Q̅ в _рисунках I.2-13_ и _I.3-6_.
@@ -22,7 +156,7 @@
</details>
<br><br>
<br>
**27.10.2025**: Исправлена опечатка в описании функционального поведения ведомой защёлки в составе D-триггера на стр. 41:
@@ -38,7 +172,7 @@
</details>
<br><br>
<br>
**22.05.2025**: Исправлено несоответствие в названиях модулей в ЛР10-12.
@@ -56,7 +190,7 @@ _Рисунок II.12-3. Структурная схема блока приор
</details>
<br><br>
<br>
**13.05.2025**: Исправлен рисунок II.8-3 — исправлена опечатка в названии нижнего сигнала (`mem_wd_i``mem_wd_o`).
@@ -85,7 +219,7 @@ _Рисунок II.12-3. Структурная схема блока приор
</details>
<br><br>
<br>
**11.07.2025**: Обнаружена ошибка вёрстки в примере использования битовых сдвигов на стр. 79. Операции по установке, очистке и чтению N-го бита выглядят следующим образом:
@@ -95,7 +229,7 @@ X = X & ~(1 << N); // Очистка N-го бита
Y = (X & (1 << N)) != 0; // Чтение N-го бита
```
<br><br>
<br>
**11.07.2025**: Исправлена опечатка в предпоследнем абзаце стр. 227 (в конце первого предложения должен был быть написан **LMA**):
@@ -111,13 +245,13 @@ Y = (X & (1 << N)) != 0; // Чтение N-го бита
</details>
<br><br>
<br>
**16.06.2025**: Исправлена ошибка в _листинге II.14-2_.
Предпоследнюю инструкцию (`lw a0, 40(a0)`) следует читать как `lw a0, 24(a0)`.
<br><br>
<br>
**29.03.2025**: Исправлен рисунок II.4-4 — убрана логика безусловного перехода, т.к. она должна была появиться только в следующем параграфе.

View File

@@ -79,7 +79,7 @@ _Рисунок 4. УГО логического вентиля **НЕ**._
Также существуют вариации базовых вентилей, такие как **И-НЕ**, **ИЛИ-НЕ**, **Исключающее ИЛИ-НЕ**, отличающиеся от исходных тем, что результат операции инвертирован относительно результата аналогичной операции без **-НЕ**.
Логические вентили строятся из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
Логические вентили могут быть построены из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
Особенностью современных интегральных схем является то, что они строятся на основе комплементарной (взаимодополняющей) пары транзисторов **P** и **N**-типа (**Комплементарная Металл-Оксид-Полупроводниковая**, **КМОП** логика). Для данного типа транзисторов оказалось эффективнее реализовать операции **И-НЕ** и **ИЛИ-НЕ**.

View File

@@ -78,6 +78,6 @@ endmodule
1. [Intel 4004 — 50th Anniversary Project](https://www.4004.com/mcs4-masks-schematics-sim.html);
2. [Страница википедии по Intel 4004](https://en.wikipedia.org/wiki/Intel_4004);
3. [F.Ka˘gan. Gürkaynak / Side Channel Attack Secure Cryptographic Accelerators](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf);
4. [FIPS 197, Advanced Encryption Standart (AES)](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf);
3. [F.Kağan. Gürkaynak / Side Channel Attack Secure Cryptographic Accelerators](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf);
4. [FIPS 197, Advanced Encryption Standard (AES)](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf);
5. [P. Flake, P. Moorby, S. Golson, A. Salz, S. Davidmann / Verilog HDL and Its Ancestors and Descendants](https://dl.acm.org/doi/pdf/10.1145/3386337).

View File

@@ -190,7 +190,7 @@ _Рисунок 5. Схема 4-битного сумматора._
Как же реализовать модуль, состоящий из цепочки других модулей? Половину этой задачи мы уже сделали, когда писали тестбенч к 1-битному полусумматору в _Листинге 2_ — мы создавали модуль внутри другого модуля и подключали к нему провода. Теперь надо сделать то же самое, только с чуть большим числом модулей.
Описание 4-битного сумматора, сводится к описанию межсоединения четырёх экземпляров 1-битного сумматора. Подробней о том, как описывать создание экземпляров модулей рассказано в главе [Описание модулей на языке SystemVerilog](../../Basic%20Verilog%20structures/Modules.md#Иерархия-модулей), который вы изучали перед лабораторной работой.
Описание 4-битного сумматора, сводится к описанию межсоединения четырёх экземпляров 1-битного сумматора. Подробнее о том, как описывать создание экземпляров модулей рассказано в главе [Описание модулей на языке SystemVerilog](../../Basic%20Verilog%20structures/Modules.md#Иерархия-модулей), который вы изучали перед лабораторной работой.
![../../.pic/Labs/lab_01_adder/fig_06.png](../../.pic/Labs/lab_01_adder/fig_06.png)
@@ -280,7 +280,7 @@ example1 instance_array[7:0]( // Создается массив из 8 моду
// как есть ко всем модулям в массиве.
.c(C[7:0]), // Поскольку разрядность сигнала C не равна
// ни разрядности входа c, ни его увосьмиренной
// ни разрядности входа c, ни его увосьмерённой
// разрядности, мы должны выбрать такой диапазон
// бит, который будет удовлетворять одному из
// этих требований.

View File

@@ -1,6 +1,6 @@
# Лабораторная работа №2. Арифметико-логическое устройство
Так как основной задачей процессора является обработка цифровых данных, одним из его основных блоков является арифметико-логическое устройство (АЛУ). Задача АЛУ производить над входными данным арифметические и поразрядно логические операции.
Так как основной задачей процессора является обработка цифровых данных, одним из его основных блоков является арифметико-логическое устройство (АЛУ). Задача АЛУ производить над входными данными арифметические и поразрядно логические операции.
## Цель
@@ -12,7 +12,7 @@
- способами описания [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) на языке SystemVerilog.
## Общий ход выполнения работы
## Ход работы
1. Изучить устройство и принцип работы АЛУ (раздел [#теория](#Теория))
2. Изучить языковые конструкции SystemVerilog для реализации АЛУ (раздел [#инструменты](#Инструменты))
@@ -234,7 +234,7 @@ endmodule
Для удобства чтения, список инструкций разбит на две таблицы.
В первой таблице перечислены операции, вычисляющие значение сигнала `result_o`. **При любом коде операции, не входящим в эту таблицу, сигнал `result_o` должен быть равен нулю**.
В первой таблице перечислены операции, вычисляющие значение сигнала `result_o`. **При получении АЛУ любого кода операции, не входящего в эту таблицу, сигнал `result_o` должен быть равен нулю**.
|Операция|={cmp, mod, opcode}|Выражение | Действие |
|--------|-------------------|-----------------------|-------------------------------------------------------|
@@ -251,7 +251,7 @@ endmodule
_Таблица 1. Список вычислительных операций._
Во второй таблице перечислены операции, вычисляющие значение сигнала `flag_o`. **При любом коде операции, не входящим в эту таблицу, сигнал flag_o должен быть равен нулю**.
Во второй таблице перечислены операции, вычисляющие значение сигнала `flag_o`. **При получении АЛУ любого кода операции, не входящего в эту таблицу, сигнал `flag_o` должен быть равен нулю**.
|Операция|={cmp, mod, opcode}| Выражение | Действие |
|--------|-------------------|----------------------|-----------------------------------|

View File

@@ -139,7 +139,7 @@ endtask
task direct_test();
logic [4:0] flag_opcodes_1[6] = {ALU_SLTS, ALU_SLTU, ALU_LTS, ALU_GES, ALU_LTU, ALU_GEU};
logic [4:0] flag_opcodes_1[8] = {ALU_SLTS, ALU_SLTU, ALU_LTS, ALU_GES, ALU_LTU, ALU_GEU, ALU_EQ, ALU_NE};
logic [4:0] flag_opcodes_2[3] = {ALU_SLL, ALU_SRL, ALU_SRA};
logic [4:0] flag_opcodes_3[2] = {ALU_ADD, ALU_SUB};
logic [4:0] flag_opcodes_4[5] = {ALU_XOR, ALU_OR, ALU_AND, ALU_EQ, ALU_NE};

View File

@@ -100,7 +100,7 @@ logic [19:0] memory3 [15:0]; // memory3 будет такой же память
// лабораторных работ будет скорее минусом).
logic [19:0] memory3 [1:16]; // А вот memory3 хоть и совпадает по
logic [19:0] memory4 [1:16]; // А вот memory4 хоть и совпадает по
// размеру с предыдущими реализациями,
// но отличается по адресному пространству
// обращение по нулевому адресу выдаст
@@ -328,7 +328,7 @@ module register_file(
```
По адресу `0` должно всегда считываться значение `0` вне зависимости от того, какое значение в этой ячейке памяти, и есть ли она вообще. Такая особенность обусловлена тем, что при выполнении операций очень часто используется ноль (сравнение с нулём, инициализация переменных нулевым значением, копирование значения одного регистра в другой посредством сложения с нулём и записи результата и т.п.). Эту особенность регистрового файла можно реализовать несколькими способами:
По спецификации RISC-V, нулевой регистр регистрового файла является аппаратным нулём [[2](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), стр. 21]. Это значит, что по адресу `0` должно всегда считываться значение `0` вне зависимости от того, какое значение в этой ячейке памяти, и есть ли она вообще. Такая особенность обусловлена тем, что при выполнении операций очень часто используется ноль (сравнение с нулём, инициализация переменных нулевым значением, копирование значения одного регистра в другой посредством сложения с нулём и записи результата и т.п.). Эту особенность регистрового файла можно реализовать несколькими способами:
- с помощью мультиплексора, управляющим сигналом которого является результат сравнения адреса на чтение с нулём;
- либо же можно проинициализировать нулевую ячейку памяти нулём с запретом записи в неё каких-либо значений. В этом случае в ячейке всегда будет ноль, а значит и считываться с нулевого адреса будет только он.

View File

@@ -271,8 +271,8 @@ _Рисунок 5. Реализация безусловного переход
1. 10 вычислительных инструкций `0 0 01 alu_op RA1 RA2 xxxx xxxx WA`
2. Инструкция загрузки константы `0 0 00 const WA`
3. Инструкция загрузки из внешних устройств `0 0 10 xxx xxxx xxxx xxxx xxxx xxxx WA`
4. Безусловный переход `1 x xx xxx xxxx xxxx xxxx const xxxxx`
5. 6 инструкций условного перехода `0 1 xx alu_op RA1 RA2 const xxxxx`
4. Безусловный переход `1 x xx xxx xxxx xxxx xxxx offset xxxxx`
5. 6 инструкций условного перехода `0 1 xx alu_op RA1 RA2 offset xxxxx`
При кодировании инструкций используются следующие поля:
@@ -356,7 +356,7 @@ endmodule
1. Добавьте в `Design Sources` проекта файл [program.mem](program.mem), содержащий программу из Листинга 1.
2. Опишите модуль `CYBERcobra` с таким же именем и портами, как указано в задании (обратите внимание на регистр имени модуля).
1. В первую очередь, необходимо создать счётчик команд и все вспомогательные провода. При создании, **следите за разрядностью**.
2. Затем, необходимо создать экземпляры модулей: памяти инструкции, АЛУ, регистрового файла и сумматора. При подключении сигналов сумматора, надо **обязательно** надо подать нулевое значение на входной бит переноса. Выходной бит переноса подключать не обязательно. Объекту памяти инструкций нужно дать имя `imem`.
2. Затем, необходимо создать экземпляры модулей: памяти инструкции, АЛУ, регистрового файла и сумматора. При подключении сигналов сумматора, надо **обязательно** подать нулевое значение на входной бит переноса. Выходной бит переноса подключать не обязательно. Объекту памяти инструкций нужно дать имя `imem`.
3. После этого, необходимо описать оставшуюся логику:
1. Программного счётчика. Счётчик должен сбрасываться, когда сигнал _rst_i == 1_.
2. Сигнала управления мультиплексором, выбирающим слагаемое для программного счётчика

View File

@@ -10,32 +10,39 @@ See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
*/
module lab_04_tb_CYBERcobra();
logic [31:0] OUT;
logic clk;
logic rst;
logic [15:0] sw_i;
CYBERcobra DUT(
.clk_i(clk),
.rst_i(rstn),
.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 #5 clk = ~clk;
always #5ns clk = ~clk;
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");
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;
#5;
$display("You're trying to run simulation that has finished. Aborting simulation.");
@(posedge clk);
$display("You're trying to run simulation that has finished.");
$display("Aborting simulation.");
$fatal();
end

View File

@@ -151,7 +151,7 @@ _Таблица 2. Значения сигнала `mem_size_o` при пере
Сигнал, который должен принять значение `1`, в случае если пришла инструкция, которая не входит в список поддерживаемых процессором.
Это не единственное, что должен сделать декодер в подобной ситуации. Давайте разберем подробней, что должно происходить по приходу нелегальной инструкции.
Это не единственное, что должен сделать декодер в подобной ситуации. Давайте разберем подробнее, что должно происходить по приходу нелегальной инструкции.
## Обработка нелегальной инструкции
@@ -338,7 +338,7 @@ _Таблица 7. Описание портов дешифратора кома
## Инструменты
**SystemVerilog** – это язык описания аппаратуры. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него нужно. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы хорошо знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. Однако, часто два разных кода, одинаковые по смыслу, могут синтезироваться в разную аппаратуру, хотя функционально они будут идентичны, но могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
**SystemVerilog** – это язык описания аппаратуры. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него требуется. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы хорошо знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. В то же время два одинаковых по смыслу кода могут синтезироваться в разную аппаратуру. Будучи функционально идентичными, они могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
Декодер – комбинационная схема. Это значит, что каждый раз подавая на вход одни и те же значения, вы будете получать на выходе один и тот же результат.
@@ -429,9 +429,9 @@ _Листинг 2. Прототип декодера инструкций._
2. Модуль может быть описан множеством способов: каждый выходной сигнал может быть описан через собственную комбинационную логику в отдельном блоке `case`, однако проще всего будет описать все сигналы через вложенные `case` внутри одного блока `always_comb`.
3. Внутри блока `always_comb` до начала блока `case` можно указать базовые значения для всех выходных сигналов. Это не то же самое, что вариант `default` в блоке `case`. Здесь вы можете описать состояния, которые будут использованы чаще всего, и в этом случае, присваивание сигналу будет выполняться только в том месте, где появится инструкция, требующая значение этого сигнала, отличное от базового.
4. Далее вы можете описать базовый блок `case`, где будет определен тип операции по ее коду.
5. Определив тип операции, вы сможете определить какая конкретно операция по полям `func3` и `func7` (если данный тип имеет такие поля).
6. Не забывайте, что в случае, если на каком-то из этапов (определения типа, или определения конкретной операции) вам приходит непредусмотренное ISA значение какого-либо поля, необходимо выставить сигнал `illegal_instr_o`.
7. В случае некорректной инструкции, вы должны гарантировать, что не произойдет условный/безусловный переход, а во внешнюю память, регистровый файл, а также регистры контроля и статуса ничего не запишется. Не важно, что будет выполняться на АЛУ, не важно какие данные будут выбраны на мультиплексоре источника записи. Важно чтобы не произошел сам факт записи в любое из устройств (подумайте какие значения для каких сигналов необходимо для этого выставить).
5. Определив тип, вы сможете понять, какая именно вам пришла операция по полям `func3` и `func7` (если данный тип имеет такие поля).
6. Не забывайте, что в случае, если на каком-то из этапов (определения типа или определения конкретной операции) вам приходит непредусмотренное ISA значение какого-либо поля, необходимо выставить сигнал `illegal_instr_o`.
7. В случае некорректной инструкции, вы должны гарантировать, что не произойдет условный/безусловный переход, а во внешнюю память, регистровый файл, а также регистры контроля и статуса ничего не запишется. Неважно, что будет выполняться на АЛУ и какие данные будут выбраны на мультиплексоре источника записи. Важно, чтобы не произошел сам факт записи в любое из устройств (подумайте, какие значения для каких сигналов необходимо для этого выставить).
4. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_05.tb_decoder.sv`](lab_05.tb_decoder.sv). Вполне возможно, что после первого запуска вы столкнётесь с сообщениями о множестве ошибок. Вам необходимо [исследовать](../../Vivado%20Basics/05.%20Bug%20hunting.md) эти ошибки на временной диаграмме и исправить их в вашем модуле.
1. Перед запуском моделирования убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
5. Данная лабораторная работа не предполагает проверки в ПЛИС

View File

@@ -1,6 +1,6 @@
# Лабораторная работа №7 "Тракт данных"
Микроархитектуру можно разделить на две части: тракт данных и устройство управления. По тракту данных перемещаются данные (из памяти инструкций, регистрового файла, АЛУ, памяти данных, мультиплексоров), а устройство управления (в нашем случае — декодер инструкций) получает текущую инструкцию из тракта и в ответ говорит ему как именно её выполнить, то есть управляет тем, как эти данные будут через проходить тракт данных.
Микроархитектуру можно разделить на две части: тракт данных и устройство управления. По тракту данных перемещаются данные (из памяти инструкций, регистрового файла, АЛУ, памяти данных, мультиплексоров), а устройство управления (в нашем случае — декодер инструкций) получает текущую инструкцию из тракта и в ответ говорит ему как именно её выполнить, то есть управляет тем, как эти данные будут проходить через тракт данных.
## Цель
@@ -69,7 +69,7 @@ _Рисунок 1. Микроархитектура ядра процессор
Программный счётчик (`PC`) теперь также изменяется более сложным образом. Поскольку появился ещё один вид безусловного перехода (`jalr`), программный счётчик может не просто увеличиться на значение константы из инструкции, но и получить совершенно новое значение в виде суммы константы и значения из регистрового файла (см. на самый левый мультиплексор _рис. 1_). Обратите внимание, что младший бит этой суммы должен быть обнулен — таково требование спецификации [[1](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), стр. 28].
Поскольку обращение во внешнюю память требует времени, необходимо приостанавливать программный счётчик, чтобы до конца обращения в память не начались исполняться последующие инструкции. Для этого у программного счётчика появился управляющий сигнал `stall_i`. Программный счётчик может меняться только когда этот сигнал равен нулю (иными словами, инверсия этого сигнала является сигналом `enable` для регистра `PC`).
Поскольку обращение во внешнюю память требует времени, необходимо приостанавливать программный счётчик, чтобы до конца обращения в память не начали исполняться последующие инструкции. Для этого у программного счётчика появился управляющий сигнал `stall_i`. Программный счётчик может меняться только когда этот сигнал равен нулю (иными словами, инверсия этого сигнала является сигналом `enable` для регистра `PC`).
### processor_system
@@ -169,7 +169,7 @@ _Листинг 2. Программа из Листинга 1, представ
## Порядок выполнения задания
1. Внимательно ознакомьтесь микроархитектурной реализацией процессорного ядра. В случае возникновения вопросов, проконсультируйтесь с преподавателем.
1. Внимательно ознакомьтесь с микроархитектурной реализацией процессорного ядра. В случае возникновения вопросов, проконсультируйтесь с преподавателем.
2. Замените файл `program.mem` в `Design Sources` проекта новым файлом [program.mem](program.mem), приложенном в данной лабораторной работе. Данный файл содержит программу из _листинга 1_.
3. Опишите модуль процессорного ядра с таким же именем и портами, как указано в задании.
1. Процесс реализации модуля похож на процесс описания модуля CYBERcobra, однако теперь появляется:

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

@@ -19,6 +19,6 @@ _Рисунок 1. Подключение LSU в процессорную сис
1. Интегрируйте модули `lsu` и `data_mem` в модуль `processor_system`.
1. Обратите внимание, что из модуля `processor_system` необходимо убрать логику сигнала `stall`, т.к. она была перемещена внутрь модуля `lsu`.
2. После интеграции модулей проверьте процессорную систему с помощью [программы](../07.%20Datapath/#Задание) и верификационного окружения из ЛР№7.
1. Как и в случае с проверкой процессора архитектуры CYBERcobra, вам не будет сказано пройден тест или нет. Вам необходимо самостоятельно, такт за тактом, проверить, что процессор правильно выполняет описанные в [_листинге 1_](../07.%20Datapath/#Задание) ЛР№7 инструкции (см. порядок выполнения задания ЛР№4). Для этого необходимо сперва самостоятельно рассчитать, что именно должна сделать данная инструкция, а потом проверить, что процессор сделал именно это.
1. Как и в случае с проверкой процессора архитектуры CYBERcobra, вам не будет сказано, пройден тест или нет. Вам необходимо самостоятельно, такт за тактом, проверить, что процессор правильно выполняет описанные в [_листинге 1_](../07.%20Datapath/#Задание) ЛР№7 инструкции (см. порядок выполнения задания ЛР№4). Для этого необходимо сперва самостоятельно рассчитать, что именно должна сделать данная инструкция, а потом проверить, что процессор сделал именно это.
2. Обратите внимание на то, как теперь исполняются инструкции `sw`, `sh`, `sb`, `lw`, `lh`, `lb`, `lhu`, `lbu`.
3. Данная лабораторная работа не предполагает проверки в ПЛИС.

View File

@@ -11,7 +11,7 @@
1. Описать модуль контроллера прерываний.
2. Описать модуль контроллера регистров статуса и контроля (**CSR**-контроллер).
## Ход выполнения
## Ход работы
1. Изучение теории по прерываниям и исключениям в архитектуре RISC-V, включая работу с регистрами статуса и контроля (**CSR**) и механизмы реализации прерываний.
2. Реализация схемы обработки прерывания для устройства на основе RISC-V
@@ -97,7 +97,7 @@ _Рисунок 1. Распределение привилегий по уров
_Таблица 1. Список регистров, подлежащих реализации в рамках лабораторной работы [[6](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/priv-isa-asciidoc.pdf), стр. 17]._
По адресу `0x304` должен располагаться регистр, позволяющий маскировать перехваты. Например, если на 5-ом входе системы прерывания генерируется прерывание, то процессор отреагирует на него только в том случае, если 5-ый бит регистра `mie` будет равен 1. Младшие 16 бит этого регистра спецификация RISC-V отводит под маскирование специальных системных прерываний [[6](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/priv-isa-asciidoc.pdf), стр. 36], которые не будут поддерживаться нашим процессором (подробней об этом будет в описании регистра mcause). Поэтому в нашей процессорной системе мы будем использовать только старшие 16 бит регистра `mie`, которые отведены для нужд конкретной платформы.
По адресу `0x304` должен располагаться регистр, позволяющий маскировать перехваты. Например, если на 5-ом входе системы прерывания генерируется прерывание, то процессор отреагирует на него только в том случае, если 5-ый бит регистра `mie` будет равен 1. Младшие 16 бит этого регистра спецификация RISC-V отводит под маскирование специальных системных прерываний [[6](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/priv-isa-asciidoc.pdf), стр. 36], которые не будут поддерживаться нашим процессором (подробнее об этом будет в описании регистра mcause). Поэтому в нашей процессорной системе мы будем использовать только старшие 16 бит регистра `mie`, которые отведены для нужд конкретной платформы.
По адресу `0x305` должен располагаться регистр `mtvec`, который состоит из двух полей: BASE[31:2] и MODE. Поле BASE хранит старшие 30 бит базового адреса обработчика перехвата (поскольку этот адрес должен быть всегда равен четырём, младшие два бита считаются равными нулю). Поле MODE кодирует тип системы прерывания:
@@ -108,7 +108,7 @@ _Таблица 1. Список регистров, подлежащих реа
_Рисунок 2. Разделение регистра `mtvec` на поля `BASE` и `MODE`[[6](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/priv-isa-asciidoc.pdf), стр. 34]_
В случае обзорной системы прерывания, любой перехват приводит к загрузке в PC значения базового адреса обработчика перехвата (`PC=BASE`). В векторной системе прерывания исключения обрабатываются таким же способом, как и в обзорной системе, а вот прерывания обрабатываются путём загрузки в PC суммы базового адреса и учетверённого значения причины прерывания (`PC=BASE+4*CAUSE`).
В случае обзорной системы прерывания, любой перехват приводит к загрузке в PC значения базового адреса обработчика перехвата (`PC=BASE`). В векторной системе исключения обрабатываются таким же способом, как и в обзорной системе, а вот прерывания обрабатываются путём загрузки в PC суммы базового адреса и учетверённого значения причины прерывания (`PC=BASE+4*CAUSE`).
В рамках данной лабораторной работы мы будем реализовывать обзорную систему прерываний. Кроме того, поскольку у обзорной системы прерываний `MODE==0`, что совпадёт с тем, что два младших бита базового адреса обработчика перехвата должны быть равны нулю, при перехвате мы можем присваивать программному счётчику значение `mtvec` без каких-либо преобразований.
@@ -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

@@ -28,8 +28,6 @@ int err_count;
always #5 clk_i <= ~clk_i;
initial begin
$display("\n\n===========================\n\nPress button 'Run All' (F3)\n\n===========================\n\n");
$stop();
clk_i = '0;
exception_i = '0;
mret_i = '0;
@@ -383,9 +381,21 @@ endtask
//logic irq, irq_ret;
task error_info(irq, irq_ret);
if (irq_o!==irq) begin $error("invalid irq_o = %b, expected value %b." , $sampled(irq_o ), irq ); err_count++; end
if (irq_ret_o!==irq_ret) begin $error("invalid irq_ret_o = %b, expected value %b." , $sampled(irq_ret_o), irq_ret); err_count++; end
if (irq_cause_o!==32'h8000_0010) begin $error("invalid irq_cause_o = %h, expected value 32'h8000_0010.", $sampled(irq_cause_o) ); err_count++; end
if (irq_o!==irq) begin $error("invalid irq_o = %1b, expected value %b." , $sampled(irq_o ), irq ); err_count++; end
if (irq_ret_o!==irq_ret) begin $error("invalid irq_ret_o = %1b, expected value %b." , $sampled(irq_ret_o), irq_ret); err_count++; end
if (irq_cause_o!==32'h8000_0010) begin $error("invalid irq_cause_o = %08h, expected value 32'h8000_0010.", $sampled(irq_cause_o) ); err_count++; end
endtask
initial begin
automatic int not_stopped = 1;
forever begin
@(posedge clk_i);
if((err_count >= 10) && not_stopped) begin
$display("Simulation stopped after ten errors.");
$stop();
not_stopped = 0;
end
end
end
endmodule

View File

@@ -36,7 +36,7 @@ module lab_11_tb_processor_system();
rst = 0;
repeat(20)@(posedge clk);
DUT.irq_req = 1;
while(DUT.irq_ret == 0) begin
while(DUT.irq_ret !== 1) begin
@(posedge clk);
end
DUT.irq_req = 0;

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,7 +82,7 @@ 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 )

View File

@@ -16,7 +16,7 @@ module lab_15_tb_system();
logic flash_rx;
logic tx_o;
logic ps2_clk, ps2_dat;
logic sw_i;
logic [15:0] sw_i;
logic tb_rx;
logic flashing_is_done = 0;
logic core_reset;
@@ -101,7 +101,7 @@ module lab_15_tb_system();
end
system DUT(
processor_system DUT(
.clk_i (clk_i ),
.resetn_i (!rst_i ),
.rx_i (flashing_is_done ? tb_rx : flash_rx ),

View File

@@ -17,7 +17,7 @@ OBJCOPY = $(CC_PATH)/$(CC_PREFIX)-objcopy
SIZE = $(CC_PATH)/$(CC_PREFIX)-size
OBJS = core_main.o core_list_join.o core_matrix.o core_state.o core_util.o \
barebones/core_portme.o barebones/startup.o barebones/cvt.o \
startup.o barebones/core_portme.o barebones/cvt.o \
barebones/ee_printf.o

View File

@@ -43,7 +43,7 @@
### Таймер
Разберемся с тем, как будет работать наш таймер. По сути, это просто системный счётчик (не путайте с программным счётчиком), непрерывно считающий такты с момента последнего сброса. Системным он называется потому, что работает на системной тактовой частоте. Значения частот, на которых работают процессорные системы сопоставимы с 32-битными значениями, поэтому системный счётчик должен быть 64-битным. Для измерения времени мы будем засекать значение счётчика на момент начала отсчета и значение счётчика в конце отсчёта. Зная тактовую частоту и разность между значениями счётчика мы с легкостью сможем вычислить прошедшее время. При этом нужно обеспечить счётчик такой разрядностью, чтобы он точно не смог переполниться.
Разберемся с тем, как будет работать наш таймер. По сути, это просто системный счётчик (не путайте с программным счётчиком), непрерывно считающий такты с момента последнего сброса. Значения частот, на которых работают процессорные системы сопоставимы с 32-битными значениями, поэтому системный счётчик должен быть 64-битным. Для измерения времени мы будем засекать значение счётчика на момент начала отсчета и значение счётчика в конце отсчёта. Зная тактовую частоту и разность между значениями счётчика мы с легкостью сможем вычислить прошедшее время. При этом нужно обеспечить счётчик такой разрядностью, чтобы он точно не смог переполниться.
Поскольку мы уже назвали данный модуль "таймером", чтобы тот не был слишком простым, давайте добавим ему функциональности: пускай это будет устройство, способное генерировать прерывание через заданное число тактов. Таким образом, процессорная система сможет засекать время без постоянного опроса счётчика. Для работы coremark эта функциональность не нужна — если ее реализация окажется слишком сложной для вас, просто создайте системный счётчик, инкрементирующийся каждый такт, с доступом на чтение по адресу `32'h0`.
@@ -210,6 +210,15 @@ _Листинг 4. Код функции `uart_send_char`._
### Компиляция
> «Я нашёл этому поистине чудесное доказательство, но поля книги слишком узки для него».
> — Пьер де Ферма
Репозиторий CoreMark содержит встроенную систему сборки, основанную на утилите `make`, с возможностью добавления пользовательских платформ. При корректной интеграции платформы программу можно было бы собрать, запрограммировать ею микроконтроллер и получить результат выполнения одной командой.
Однако для описания такого подхода потребовалась бы отдельная глава, посвящённая системе сборки, утилите `make` и Python-скрипту, отвечающему за программирование микроконтроллера. Поэтому в данном параграфе авторы выбрали более простой путь — заменили исходную систему сборки собственной, упрощённой реализацией, поддерживающей только нашу платформу.
Ознакомиться с корректным способом интеграции можно в репозитории [github.com/MPSU/APS-coremark](https://github.com/MPSU/APS-coremark).
Для компиляции программы, вам потребуются предоставленные файлы [Makefile](Makefile) и [linker_script.ld](linker_script.ld), а также файл [startup.S](../14.%20Programming/startup.S) из ЛР№14. Эти файлы необходимо скопировать с заменой в корень папки с программой.
`Makefile` написан из расчёта, что кросс-компилятор расположен по пути `C:/riscv_cc/`. В случае, если это не так, измените первую строчку данного файла в соответствии с расположением кросс-компилятора.
@@ -363,7 +372,7 @@ Iterations/Sec : 3.446111
Более того, при сравнении с другими результатами, необходимо учитывать флаги оптимизации, которые использовались при компиляции программы, поскольку они также влияют на результат. Например, если собрать coremark с уровнем оптимизаций `-O1`, результат нашей системы скакнёт до 11.23 кормарков, что всего лишь является следствием того, что программа стала меньше обращаться к памяти после оптимизаций. Именно поэтому результаты coremark указываются вместе с опциями, с которыми тот был собран.
Мы не будем уходить в дебри темных паттернов маркетинга и вместо этого будет оценивать производительность в лоб: сколько кормарков в секунду смог прогнать наш процессор без каких-либо оптимизаций в сравнении с представленными результатами других систем вне зависимости от их оптимизаций.
Мы не будем уходить в дебри темных паттернов маркетинга и вместо этого будем оценивать производительность в лоб: сколько кормарков в секунду смог прогнать наш процессор без каких-либо оптимизаций в сравнении с представленными результатами других систем вне зависимости от их оптимизаций.
Таблица опубликованных результатов находится по адресу: [https://www.eembc.org/coremark/scores.php](https://www.eembc.org/coremark/scores.php). Нам необходимо отсортировать эту таблицу по столбцу `CoreMark`, кликнув по нему.

View File

@@ -139,7 +139,7 @@ endmodule
module testbench();
logic A, B, C;
adder DUT(
half_adder DUT(
.A(A), // <- здесь будет ошибка,
// т.к. в модуле half_adder нет порта 'A'
.b(B),

View File

@@ -29,7 +29,7 @@
## Дэвид М. Харрис и Сара Л. Харрис: Цифровая схемотехника и архитектура компьютера: RISC-V
Потрясающая книга, являющаяся более доступным вариантом изложения и иллюстрации книги "Архитектура компьютера и проектирование компьютерных систем", Паттерсона и Хеннесси. На примере архитектуры **RISC-V** рассказывается как построить процессор начиная с вопросов работы транзистора. Рассматриваются базовые конструкции языков описания аппаратуры **SystemVerilog** и **VHDL**. Эту книгу на чистом энтузиазме перевели на русский язык группа ученых и инженеров из стран бывшего СССР с подачи [Юрия Панчула](http://panchul.com/about_ru/). Электронный вариант для архитектуры **MIPS** распространяется бесплатно и абсолютно легально. Обязательна к ознакомлению каждому! Гораздо удобнее использовать печатный вариант, на этот случай ее можно приобрести [тут](https://dmkpress.com/catalog/electronics/circuit_design/978-5-97060-961-3/). Электронный вариант с архитектурой **MIPS** доступен в облаке и [электронной библотеке](https://e.lanbook.com/book/241166).
Потрясающая книга, являющаяся более доступным вариантом изложения и иллюстрации книги "Архитектура компьютера и проектирование компьютерных систем", Паттерсона и Хеннесси. На примере архитектуры **RISC-V** рассказывается как построить процессор начиная с вопросов работы транзистора. Рассматриваются базовые конструкции языков описания аппаратуры **SystemVerilog** и **VHDL**. Эту книгу на чистом энтузиазме перевели на русский язык группа ученых и инженеров из стран бывшего СССР с подачи [Юрия Панчула](http://panchul.com/about_ru/). Электронный вариант для архитектуры **MIPS** распространяется бесплатно и абсолютно легально. Обязательна к ознакомлению каждому! Гораздо удобнее использовать печатный вариант, на этот случай ее можно приобрести [тут](https://dmkpress.com/catalog/electronics/circuit_design/978-5-97060-961-3/). Электронный вариант с архитектурой **RISC-V** доступен в [электронной библотеке](https://e.lanbook.com/book/241166).
![../.pic/Other/Further%20readings/harris.png](../.pic/Other/Further%20readings/harris.png)

View File

@@ -51,7 +51,7 @@ Readme.md
Здесь находятся методические материалы ко всем 16 лабораторным работам, разложенные по соответствующим им папкам.
Практически в каждой такой папке находится файл формата `lab_xx.tb_xxx.sv` — это файл с верификационным окружением для данной лабораторной работы. Такой файл необходимо добавлять в _Simulation Sources_ проекта (подробней в разделе _Vivado Basics_).
Практически в каждой такой папке находится файл формата `lab_xx.tb_xxx.sv` — это файл с верификационным окружением для данной лабораторной работы. Такой файл необходимо добавлять в _Simulation Sources_ проекта (подробнее в разделе _Vivado Basics_).
Кроме того, в папке лабораторной работы могут находиться `xxx_pkg.sv` и `xxx.mem` файлы, содержащие соответственно параметры и данные, которыми необходимо проинициализировать память устройства. Такие файлы будет необходимо добавлять в _Design Sources_ проекта.