Compare commits

..

15 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
26 changed files with 518 additions and 2093 deletions

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"]

10
.github/prepare.sh vendored
View File

@@ -1,4 +1,10 @@
#!/bin/bash
set -e
mkdir src
cp .github/book.toml .github/*.md ./
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,59 +1,102 @@
# 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
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
url: ${{ steps.deployment.outputs.page_url }}
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:

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

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),

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

@@ -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,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** точно также одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. В то же время два одинаковых по смыслу кода могут синтезироваться в разную аппаратуру. Будучи функционально идентичными, они могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
Декодер – комбинационная схема. Это значит, что каждый раз подавая на вход одни и те же значения, вы будете получать на выходе один и тот же результат.
@@ -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

@@ -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

@@ -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;

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

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