Compare commits
19 Commits
98db9682dd
...
russian_ve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4676bf3b77 | ||
|
|
a64da6312b | ||
|
|
bfb6bac9d5 | ||
|
|
4aa7ed1be8 | ||
|
|
4313c22bee | ||
|
|
007889f849 | ||
|
|
e09e48adff | ||
|
|
8ffbc7a01b | ||
|
|
da422cfccb | ||
|
|
71cb2f3099 | ||
|
|
63260f434e | ||
|
|
1034565000 | ||
|
|
ccf769f48f | ||
|
|
44910a0b57 | ||
|
|
a424d5c40f | ||
|
|
896f7fccda | ||
|
|
40074bcb25 | ||
|
|
b480505e11 | ||
|
|
59b569a1e4 |
4
.github/book.toml
vendored
@@ -1,10 +1,12 @@
|
|||||||
[book]
|
[book]
|
||||||
authors = ["Andrei Solodovnikov, Mikhail Popov"]
|
authors = ["Andrei Solodovnikov, Mikhail Popov"]
|
||||||
language = "ru"
|
language = "ru"
|
||||||
multilingual = true
|
|
||||||
src = "./"
|
src = "./"
|
||||||
title = "Архитектуры процессорных систем"
|
title = "Архитектуры процессорных систем"
|
||||||
|
|
||||||
[output.html]
|
[output.html]
|
||||||
git-repository-url = "https://github.com/MPSU/APS"
|
git-repository-url = "https://github.com/MPSU/APS"
|
||||||
git-repository-icon = "fa-github"
|
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
@@ -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
@@ -1,4 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
mkdir src
|
mkdir -p src
|
||||||
cp .github/book.toml .github/*.md ./
|
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
@@ -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
@@ -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();
|
||||||
|
}
|
||||||
|
})();
|
||||||
79
.github/workflows/mdbook.yml
vendored
@@ -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
|
name: Deploy mdBook site to Pages
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# Runs on pushes targeting the default branch
|
|
||||||
push:
|
push:
|
||||||
branches: ["master"]
|
branches: ["master", "english_version"]
|
||||||
|
|
||||||
# Allows you to run this workflow manually from the Actions tab
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pages: write
|
pages: write
|
||||||
id-token: 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:
|
concurrency:
|
||||||
group: "pages"
|
group: "pages"
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Build job
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
MDBOOK_VERSION: 0.4.36
|
MDBOOK_VERSION: 0.4.36
|
||||||
|
|
||||||
steps:
|
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
|
- 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: |
|
run: |
|
||||||
chmod +x .github/prepare.sh
|
chmod +x .github/prepare.sh
|
||||||
.github/prepare.sh
|
.github/prepare.sh
|
||||||
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
|
|
||||||
rustup update
|
- name: Build Russian (mdbook → ./book/)
|
||||||
cargo install --version ${MDBOOK_VERSION} mdbook
|
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
|
- name: Setup Pages
|
||||||
id: pages
|
id: pages
|
||||||
uses: actions/configure-pages@v5
|
uses: actions/configure-pages@v5
|
||||||
- name: Build with mdBook
|
|
||||||
run: mdbook build
|
- name: Upload Pages artifact
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-pages-artifact@v3
|
uses: actions/upload-pages-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: ./book
|
path: ./book
|
||||||
|
|
||||||
# Deployment job
|
|
||||||
deploy:
|
deploy:
|
||||||
environment:
|
environment:
|
||||||
name: github-pages
|
name: github-pages
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 153 KiB |
@@ -32,7 +32,7 @@ endmodule
|
|||||||
module testbench();
|
module testbench();
|
||||||
logic A, B, C;
|
logic A, B, C;
|
||||||
|
|
||||||
adder DUT(
|
half_adder DUT(
|
||||||
.A(A), // <- здесь будет ошибка,
|
.A(A), // <- здесь будет ошибка,
|
||||||
// т.к. в модуле half_adder нет порта 'A'
|
// т.к. в модуле half_adder нет порта 'A'
|
||||||
.b(B),
|
.b(B),
|
||||||
|
|||||||
116
ERRATA.md
@@ -2,6 +2,122 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
**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`.
|
**30.12.2025**: В Финальном обзоре ЛР№4 (стр. 111) указан неверный тип константы для инструкций переходов: 23-битная `const`, в то время как на самом деле используется 8-битная `offset`.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ _Рисунок 4. УГО логического вентиля **НЕ**._
|
|||||||
|
|
||||||
Также существуют вариации базовых вентилей, такие как **И-НЕ**, **ИЛИ-НЕ**, **Исключающее ИЛИ-НЕ**, отличающиеся от исходных тем, что результат операции инвертирован относительно результата аналогичной операции без **-НЕ**.
|
Также существуют вариации базовых вентилей, такие как **И-НЕ**, **ИЛИ-НЕ**, **Исключающее ИЛИ-НЕ**, отличающиеся от исходных тем, что результат операции инвертирован относительно результата аналогичной операции без **-НЕ**.
|
||||||
|
|
||||||
Логические вентили строятся из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
|
Логические вентили могут быть построены из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
|
||||||
|
|
||||||
Особенностью современных интегральных схем является то, что они строятся на основе комплементарной (взаимодополняющей) пары транзисторов **P** и **N**-типа (**Комплементарная Металл-Оксид-Полупроводниковая**, **КМОП** логика). Для данного типа транзисторов оказалось эффективнее реализовать операции **И-НЕ** и **ИЛИ-НЕ**.
|
Особенностью современных интегральных схем является то, что они строятся на основе комплементарной (взаимодополняющей) пары транзисторов **P** и **N**-типа (**Комплементарная Металл-Оксид-Полупроводниковая**, **КМОП** логика). Для данного типа транзисторов оказалось эффективнее реализовать операции **И-НЕ** и **ИЛИ-НЕ**.
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,6 @@ endmodule
|
|||||||
|
|
||||||
1. [Intel 4004 — 50th Anniversary Project](https://www.4004.com/mcs4-masks-schematics-sim.html);
|
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);
|
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);
|
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 Standart (AES)](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.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).
|
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).
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
- способами описания [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) на языке SystemVerilog.
|
- способами описания [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) на языке SystemVerilog.
|
||||||
|
|
||||||
## Общий ход выполнения работы
|
## Ход работы
|
||||||
|
|
||||||
1. Изучить устройство и принцип работы АЛУ (раздел [#теория](#Теория))
|
1. Изучить устройство и принцип работы АЛУ (раздел [#теория](#Теория))
|
||||||
2. Изучить языковые конструкции SystemVerilog для реализации АЛУ (раздел [#инструменты](#Инструменты))
|
2. Изучить языковые конструкции SystemVerilog для реализации АЛУ (раздел [#инструменты](#Инструменты))
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ endmodule
|
|||||||
1. Добавьте в `Design Sources` проекта файл [program.mem](program.mem), содержащий программу из Листинга 1.
|
1. Добавьте в `Design Sources` проекта файл [program.mem](program.mem), содержащий программу из Листинга 1.
|
||||||
2. Опишите модуль `CYBERcobra` с таким же именем и портами, как указано в задании (обратите внимание на регистр имени модуля).
|
2. Опишите модуль `CYBERcobra` с таким же именем и портами, как указано в задании (обратите внимание на регистр имени модуля).
|
||||||
1. В первую очередь, необходимо создать счётчик команд и все вспомогательные провода. При создании, **следите за разрядностью**.
|
1. В первую очередь, необходимо создать счётчик команд и все вспомогательные провода. При создании, **следите за разрядностью**.
|
||||||
2. Затем, необходимо создать экземпляры модулей: памяти инструкции, АЛУ, регистрового файла и сумматора. При подключении сигналов сумматора, надо **обязательно** надо подать нулевое значение на входной бит переноса. Выходной бит переноса подключать не обязательно. Объекту памяти инструкций нужно дать имя `imem`.
|
2. Затем, необходимо создать экземпляры модулей: памяти инструкции, АЛУ, регистрового файла и сумматора. При подключении сигналов сумматора, надо **обязательно** подать нулевое значение на входной бит переноса. Выходной бит переноса подключать не обязательно. Объекту памяти инструкций нужно дать имя `imem`.
|
||||||
3. После этого, необходимо описать оставшуюся логику:
|
3. После этого, необходимо описать оставшуюся логику:
|
||||||
1. Программного счётчика. Счётчик должен сбрасываться, когда сигнал _rst_i == 1_.
|
1. Программного счётчика. Счётчик должен сбрасываться, когда сигнал _rst_i == 1_.
|
||||||
2. Сигнала управления мультиплексором, выбирающим слагаемое для программного счётчика
|
2. Сигнала управления мультиплексором, выбирающим слагаемое для программного счётчика
|
||||||
|
|||||||
@@ -10,32 +10,39 @@ See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
|
|||||||
*/
|
*/
|
||||||
module lab_04_tb_CYBERcobra();
|
module lab_04_tb_CYBERcobra();
|
||||||
|
|
||||||
|
logic [31:0] OUT;
|
||||||
|
logic clk;
|
||||||
|
logic rst;
|
||||||
|
logic [15:0] sw_i;
|
||||||
|
|
||||||
|
|
||||||
CYBERcobra DUT(
|
CYBERcobra DUT(
|
||||||
.clk_i(clk),
|
.clk_i(clk),
|
||||||
.rst_i(rstn),
|
.rst_i(rst),
|
||||||
.sw_i (sw_i),
|
.sw_i (sw_i),
|
||||||
.out_o(OUT)
|
.out_o(OUT)
|
||||||
);
|
);
|
||||||
|
|
||||||
wire [31:0] OUT;
|
|
||||||
reg clk;
|
|
||||||
reg rstn;
|
|
||||||
reg [15:0] sw_i;
|
|
||||||
|
|
||||||
initial clk <= 0;
|
initial clk <= 0;
|
||||||
always #5 clk = ~clk;
|
always #5ns clk = ~clk;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
logic [15:0] count_num;
|
||||||
$display("Test has been started");
|
$display("Test has been started");
|
||||||
rstn = 1'b1;
|
rst = 1'b1;
|
||||||
#10;
|
repeat(2)@(posedge clk);
|
||||||
rstn = 1'b0;
|
rst = 1'b0;
|
||||||
sw_i = 16'b100001000; //значение, до которого считает счетчик
|
count_num = $urandom_range(5, 10);
|
||||||
#10000;
|
sw_i = count_num;
|
||||||
$display("\n The test is over \n See the internal signals of the CYBERcobra on the waveform \n");
|
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;
|
$finish;
|
||||||
#5;
|
@(posedge clk);
|
||||||
$display("You're trying to run simulation that has finished. Aborting simulation.");
|
$display("You're trying to run simulation that has finished.");
|
||||||
|
$display("Aborting simulation.");
|
||||||
$fatal();
|
$fatal();
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ _Таблица 7. Описание портов дешифратора кома
|
|||||||
|
|
||||||
## Инструменты
|
## Инструменты
|
||||||
|
|
||||||
**SystemVerilog** – это язык описания аппаратуры. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору – как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него нужно. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы хорошо знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также – одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. Однако, часто два разных кода, одинаковые по смыслу, могут синтезироваться в разную аппаратуру, хотя функционально они будут идентичны, но могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
|
**SystemVerilog** – это язык описания аппаратуры. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору – как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него требуется. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы хорошо знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также – одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. В то же время два одинаковых по смыслу кода могут синтезироваться в разную аппаратуру. Будучи функционально идентичными, они могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
|
||||||
|
|
||||||
Декодер – комбинационная схема. Это значит, что каждый раз подавая на вход одни и те же значения, вы будете получать на выходе один и тот же результат.
|
Декодер – комбинационная схема. Это значит, что каждый раз подавая на вход одни и те же значения, вы будете получать на выходе один и тот же результат.
|
||||||
|
|
||||||
@@ -429,9 +429,9 @@ _Листинг 2. Прототип декодера инструкций._
|
|||||||
2. Модуль может быть описан множеством способов: каждый выходной сигнал может быть описан через собственную комбинационную логику в отдельном блоке `case`, однако проще всего будет описать все сигналы через вложенные `case` внутри одного блока `always_comb`.
|
2. Модуль может быть описан множеством способов: каждый выходной сигнал может быть описан через собственную комбинационную логику в отдельном блоке `case`, однако проще всего будет описать все сигналы через вложенные `case` внутри одного блока `always_comb`.
|
||||||
3. Внутри блока `always_comb` до начала блока `case` можно указать базовые значения для всех выходных сигналов. Это не то же самое, что вариант `default` в блоке `case`. Здесь вы можете описать состояния, которые будут использованы чаще всего, и в этом случае, присваивание сигналу будет выполняться только в том месте, где появится инструкция, требующая значение этого сигнала, отличное от базового.
|
3. Внутри блока `always_comb` до начала блока `case` можно указать базовые значения для всех выходных сигналов. Это не то же самое, что вариант `default` в блоке `case`. Здесь вы можете описать состояния, которые будут использованы чаще всего, и в этом случае, присваивание сигналу будет выполняться только в том месте, где появится инструкция, требующая значение этого сигнала, отличное от базового.
|
||||||
4. Далее вы можете описать базовый блок `case`, где будет определен тип операции по ее коду.
|
4. Далее вы можете описать базовый блок `case`, где будет определен тип операции по ее коду.
|
||||||
5. Определив тип операции, вы сможете определить какая конкретно операция по полям `func3` и `func7` (если данный тип имеет такие поля).
|
5. Определив тип, вы сможете понять, какая именно вам пришла операция по полям `func3` и `func7` (если данный тип имеет такие поля).
|
||||||
6. Не забывайте, что в случае, если на каком-то из этапов (определения типа, или определения конкретной операции) вам приходит непредусмотренное ISA значение какого-либо поля, необходимо выставить сигнал `illegal_instr_o`.
|
6. Не забывайте, что в случае, если на каком-то из этапов (определения типа или определения конкретной операции) вам приходит непредусмотренное ISA значение какого-либо поля, необходимо выставить сигнал `illegal_instr_o`.
|
||||||
7. В случае некорректной инструкции, вы должны гарантировать, что не произойдет условный/безусловный переход, а во внешнюю память, регистровый файл, а также регистры контроля и статуса ничего не запишется. Не важно, что будет выполняться на АЛУ, не важно какие данные будут выбраны на мультиплексоре источника записи. Важно чтобы не произошел сам факт записи в любое из устройств (подумайте какие значения для каких сигналов необходимо для этого выставить).
|
7. В случае некорректной инструкции, вы должны гарантировать, что не произойдет условный/безусловный переход, а во внешнюю память, регистровый файл, а также регистры контроля и статуса ничего не запишется. Неважно, что будет выполняться на АЛУ и какие данные будут выбраны на мультиплексоре источника записи. Важно, чтобы не произошел сам факт записи в любое из устройств (подумайте, какие значения для каких сигналов необходимо для этого выставить).
|
||||||
4. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_05.tb_decoder.sv`](lab_05.tb_decoder.sv). Вполне возможно, что после первого запуска вы столкнётесь с сообщениями о множестве ошибок. Вам необходимо [исследовать](../../Vivado%20Basics/05.%20Bug%20hunting.md) эти ошибки на временной диаграмме и исправить их в вашем модуле.
|
4. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_05.tb_decoder.sv`](lab_05.tb_decoder.sv). Вполне возможно, что после первого запуска вы столкнётесь с сообщениями о множестве ошибок. Вам необходимо [исследовать](../../Vivado%20Basics/05.%20Bug%20hunting.md) эти ошибки на временной диаграмме и исправить их в вашем модуле.
|
||||||
1. Перед запуском моделирования убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
1. Перед запуском моделирования убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
||||||
5. Данная лабораторная работа не предполагает проверки в ПЛИС
|
5. Данная лабораторная работа не предполагает проверки в ПЛИС
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Лабораторная работа №7 "Тракт данных"
|
# Лабораторная работа №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].
|
Программный счётчик (`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
|
### processor_system
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ _Листинг 2. Программа из Листинга 1, представ
|
|||||||
|
|
||||||
## Порядок выполнения задания
|
## Порядок выполнения задания
|
||||||
|
|
||||||
1. Внимательно ознакомьтесь микроархитектурной реализацией процессорного ядра. В случае возникновения вопросов, проконсультируйтесь с преподавателем.
|
1. Внимательно ознакомьтесь с микроархитектурной реализацией процессорного ядра. В случае возникновения вопросов, проконсультируйтесь с преподавателем.
|
||||||
2. Замените файл `program.mem` в `Design Sources` проекта новым файлом [program.mem](program.mem), приложенном в данной лабораторной работе. Данный файл содержит программу из _листинга 1_.
|
2. Замените файл `program.mem` в `Design Sources` проекта новым файлом [program.mem](program.mem), приложенном в данной лабораторной работе. Данный файл содержит программу из _листинга 1_.
|
||||||
3. Опишите модуль процессорного ядра с таким же именем и портами, как указано в задании.
|
3. Опишите модуль процессорного ядра с таким же именем и портами, как указано в задании.
|
||||||
1. Процесс реализации модуля похож на процесс описания модуля CYBERcobra, однако теперь появляется:
|
1. Процесс реализации модуля похож на процесс описания модуля CYBERcobra, однако теперь появляется:
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ initial begin
|
|||||||
$stop();
|
$stop();
|
||||||
not_stopped = 0;
|
not_stopped = 0;
|
||||||
end
|
end
|
||||||
@(posedge clk_i);
|
@(negedge clk_i);
|
||||||
if(!core_stall_o) begin
|
if(!core_stall_o) begin
|
||||||
core_req_i = $random;
|
core_req_i = $random;
|
||||||
core_we_i = $random;
|
core_we_i = $random;
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ _Рисунок 1. Подключение LSU в процессорную сис
|
|||||||
1. Интегрируйте модули `lsu` и `data_mem` в модуль `processor_system`.
|
1. Интегрируйте модули `lsu` и `data_mem` в модуль `processor_system`.
|
||||||
1. Обратите внимание, что из модуля `processor_system` необходимо убрать логику сигнала `stall`, т.к. она была перемещена внутрь модуля `lsu`.
|
1. Обратите внимание, что из модуля `processor_system` необходимо убрать логику сигнала `stall`, т.к. она была перемещена внутрь модуля `lsu`.
|
||||||
2. После интеграции модулей проверьте процессорную систему с помощью [программы](../07.%20Datapath/#Задание) и верификационного окружения из ЛР№7.
|
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`.
|
2. Обратите внимание на то, как теперь исполняются инструкции `sw`, `sh`, `sb`, `lw`, `lh`, `lb`, `lhu`, `lbu`.
|
||||||
3. Данная лабораторная работа не предполагает проверки в ПЛИС.
|
3. Данная лабораторная работа не предполагает проверки в ПЛИС.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
1. Описать модуль контроллера прерываний.
|
1. Описать модуль контроллера прерываний.
|
||||||
2. Описать модуль контроллера регистров статуса и контроля (**CSR**-контроллер).
|
2. Описать модуль контроллера регистров статуса и контроля (**CSR**-контроллер).
|
||||||
|
|
||||||
## Ход выполнения
|
## Ход работы
|
||||||
|
|
||||||
1. Изучение теории по прерываниям и исключениям в архитектуре RISC-V, включая работу с регистрами статуса и контроля (**CSR**) и механизмы реализации прерываний.
|
1. Изучение теории по прерываниям и исключениям в архитектуре RISC-V, включая работу с регистрами статуса и контроля (**CSR**) и механизмы реализации прерываний.
|
||||||
2. Реализация схемы обработки прерывания для устройства на основе RISC-V
|
2. Реализация схемы обработки прерывания для устройства на основе RISC-V
|
||||||
@@ -237,81 +237,74 @@ _Рисунок 5. Структурная схема контроллера пр
|
|||||||
```asm
|
```asm
|
||||||
_start:
|
_start:
|
||||||
# Инициализируем начальные значения регистров
|
# Инициализируем начальные значения регистров
|
||||||
00: li x2, 0x00003FF0 # устанавливаем указатель на верхушку стека
|
00: li x2, 0x00001F0 # устанавливаем указатель на верхушку стека
|
||||||
04: # данная псевдоинструкция будет разбита на две
|
04: li x3, 0x00000000 # устанавливаем указатель на глобальные данные
|
||||||
# инструкции: lui и addi
|
|
||||||
|
|
||||||
08: li x3, 0x00000000 # устанавливаем указатель на глобальные данные
|
08: la x5, trap_handler # псевдоинструкция la аналогично li загружает число,
|
||||||
|
# только в случае la — это число является адресом
|
||||||
0С: la x5, trap_handler # псевдоинструкция la аналогично li загружает число,
|
|
||||||
10: # только в случае la — это число является адресом
|
|
||||||
# указанного места (адресом обработчика перехвата)
|
# указанного места (адресом обработчика перехвата)
|
||||||
# данная псевдоинструкция будет разбита на две
|
|
||||||
# инструкции: lui и addi
|
|
||||||
|
|
||||||
14: csrw mtvec, x5 # устанавливаем вектор прерывания
|
0C: csrw mtvec, x5 # устанавливаем вектор прерывания
|
||||||
|
|
||||||
18: li x5, 0x00001FFC # готовим адрес верхушки стека прерывания
|
10: li x5, 0x000000F0 # готовим адрес верхушки стека прерывания
|
||||||
1С: # данная псевдоинструкция будет разбита на две
|
|
||||||
# инструкции: lui и addi
|
|
||||||
|
|
||||||
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 # начальное значение глобальной переменной
|
20: li x5, 1 # начальное значение глобальной переменной
|
||||||
30: sw x5, 0(x3) # загружаем переменную в память
|
24: sw x5, 0(x3) # загружаем переменную в память
|
||||||
|
|
||||||
34: li x6, 0 # начальное значение, чтобы в симуляции не было xxx
|
28: li x6, 0 # начальное значение, чтобы в симуляции не было xxx
|
||||||
38: li x7, 0 # начальное значение, чтобы в симуляции не было xxx
|
2C: li x7, 0 # начальное значение, чтобы в симуляции не было xxx
|
||||||
|
|
||||||
# Вызов ecall исключительно из хулиганских соображений, поскольку в данной
|
# Вызов ecall исключительно из хулиганских соображений, поскольку в данной
|
||||||
# микроархитектурной реализации это приведет к появлению illegal_instr и
|
# микроархитектурной реализации это приведет к появлению illegal_instr и
|
||||||
# последующей обработке исключения
|
# последующей обработке исключения
|
||||||
3С: ecall
|
30: ecall
|
||||||
|
|
||||||
# Вызов функции main
|
# Вызов функции main
|
||||||
main:
|
main:
|
||||||
40: beq x0, x0, main # бесконечный цикл, аналогичный while (1);
|
34: beq x0, x0, main # бесконечный цикл, аналогичный while (1);
|
||||||
|
|
||||||
# ОБРАБОТЧИК ПЕРЕХВАТА
|
# ОБРАБОТЧИК ПЕРЕХВАТА
|
||||||
# Без стороннего вмешательства процессор никогда не перейдет к инструкциям ниже,
|
# Без стороннего вмешательства процессор никогда не перейдёт к инструкциям ниже,
|
||||||
# однако в случае перехвата в программный счетчик будет загружен адрес первой
|
# однако в случае перехвата в программный счетчик будет загружен адрес первой
|
||||||
# нижележащей инструкции.
|
# нижележащей инструкции.
|
||||||
|
|
||||||
# Сохраняем используемые регистры на стек
|
# Сохраняем используемые регистры на стек
|
||||||
trap_handler:
|
trap_handler:
|
||||||
44: csrrw x5, mscratch, x5 # меняем местами mscratch и x5
|
38: csrrw x2, mscratch, x2 # меняем местами mscratch и x2
|
||||||
48: addi x5, x5, -16 # поднимаем верхушку стека на 16 байт вверх
|
3C: addi x2, x2, -16 # поднимаем верхушку стека на 16 байт вверх
|
||||||
# (указатель на стек всегда должен быть выровнен
|
# (указатель на стек всегда должен быть выровнен
|
||||||
# границе в 16 байт)
|
# по границе в 16 байт)
|
||||||
4С: sw x6, 0(x5) # сохраняем x6 на стек mscratch
|
40: sw x6, 0(x2) # сохраняем x6 на стек mscratch
|
||||||
50: sw x7, 4(x5) # сохраняем x7 на стек mscratch
|
44: sw x7, 4(x2) # сохраняем x7 на стек mscratch
|
||||||
|
|
||||||
# Проверяем произошло ли прерывание
|
# Проверяем произошло ли прерывание
|
||||||
54: csrr x6, mcause # x6 = mcause
|
48: csrr x6, mcause # x6 = mcause
|
||||||
58: li x7, 0x80000010 # загружаем в x7 код того, что произошло прерывание
|
4C: li x7, 0x80000010 # загружаем в x7 код того, что произошло прерывание
|
||||||
5С: # данная псевдоинструкция будет разбита на две
|
50: # данная псевдоинструкция будет разбита на две
|
||||||
# инструкции: lui и addi
|
# инструкции: lui и addi
|
||||||
60: bne x6, x7, exc_handler # если коды не совпадают, переходим к проверке
|
54: bne x6, x7, exc_handler # если коды не совпадают, переходим к проверке
|
||||||
# на исключение
|
# на исключение
|
||||||
# Обработчик прерывания
|
# Обработчик прерывания
|
||||||
64: lw x7, 0(x3) # загружаем переменную из памяти
|
58: lw x7, 0(x3) # загружаем переменную из памяти
|
||||||
68: addi x7, x7, 3 # прибавляем к значению 3
|
5C: addi x7, x7, 3 # прибавляем к значению 3
|
||||||
6С: sw x7, 0(x3) # возвращаем переменную в память
|
60: sw x7, 0(x3) # возвращаем переменную в память
|
||||||
70: j done # идем возвращать регистры и на выход
|
64: j done # идем возвращать регистры и на выход
|
||||||
|
|
||||||
exc_handler: # Проверяем произошло ли исключение
|
exc_handler: # Проверяем произошло ли исключение
|
||||||
74: li x7, 0x0000002 # загружаем в x7 код того, что произошло исключение
|
68: li x7, 0x0000002 # загружаем в x7 код того, что произошло исключение
|
||||||
78: bne x6, x7, done # если это не оно, то выходим
|
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
|
7C: csrw mepc, x6 # Записываем обновленное значение PC в регистр mepc
|
||||||
8С: j done # идем восстанавливать регистры со стека и на выход
|
80: j done # идем восстанавливать регистры со стека и на выход
|
||||||
|
|
||||||
# Возвращаем регистры на места и выходим
|
# Возвращаем регистры на места и выходим
|
||||||
done:
|
done:
|
||||||
90: lw x6, 0(x5) # возвращаем x6 со стека
|
84: lw x6, 0(x2) # возвращаем x6 со стека
|
||||||
94: lw x7, 4(x5) # возвращаем x7 со стека
|
88: lw x7, 4(x2) # возвращаем x7 со стека
|
||||||
98: addi x5, x5, 16 # опускаем верхушку стека обратно на 16 байт вниз
|
8C: addi x2, x2, 16 # опускаем верхушку стека обратно на 16 байт вниз
|
||||||
9С: csrrw x5, mscratch, x5 # меняем обратно местами x5 и mscratch
|
90: csrrw x2, mscratch, x2 # меняем обратно местами x2 и mscratch
|
||||||
A0: mret # возвращаем управление программе (pc = mepc)
|
94: mret # возвращаем управление программе (pc = mepc)
|
||||||
# что означает возврат в бесконечный цикл
|
# что означает возврат в бесконечный цикл
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
00004137
|
1f000113
|
||||||
FF010113
|
|
||||||
00000193
|
00000193
|
||||||
04400293
|
03800293
|
||||||
00028293
|
|
||||||
30529073
|
30529073
|
||||||
000022B7
|
0F000293
|
||||||
FFC28293
|
|
||||||
34029073
|
34029073
|
||||||
000102B7
|
FFF00293
|
||||||
30429073
|
30429073
|
||||||
00100293
|
00100293
|
||||||
0051A023
|
0051A023
|
||||||
@@ -15,10 +12,10 @@ FFC28293
|
|||||||
00000393
|
00000393
|
||||||
00000073
|
00000073
|
||||||
00000063
|
00000063
|
||||||
340292F3
|
34011173
|
||||||
ff028293
|
FF010113
|
||||||
0062A023
|
00612023
|
||||||
0072A223
|
00712223
|
||||||
34202373
|
34202373
|
||||||
800003B7
|
800003B7
|
||||||
01038393
|
01038393
|
||||||
@@ -34,8 +31,8 @@ ff028293
|
|||||||
00430313
|
00430313
|
||||||
34131073
|
34131073
|
||||||
0040006F
|
0040006F
|
||||||
0002A303
|
00012303
|
||||||
0042A383
|
00412383
|
||||||
01028293
|
01010113
|
||||||
340292F3
|
34011173
|
||||||
30200073
|
30200073
|
||||||
@@ -82,7 +82,7 @@ irq_o_is_not_0: assert property (
|
|||||||
irq_cause_o_mcause: assert property (
|
irq_cause_o_mcause: assert property (
|
||||||
@(posedge clk_i) disable iff ( rst_i )
|
@(posedge clk_i) disable iff ( rst_i )
|
||||||
irq_o |-> $onehot0(irq_cause_o[19:4])
|
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 (
|
irq_cause_o_borders: assert property (
|
||||||
@(posedge clk_i) disable iff ( rst_i )
|
@(posedge clk_i) disable iff ( rst_i )
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ module lab_15_tb_system();
|
|||||||
logic flash_rx;
|
logic flash_rx;
|
||||||
logic tx_o;
|
logic tx_o;
|
||||||
logic ps2_clk, ps2_dat;
|
logic ps2_clk, ps2_dat;
|
||||||
logic sw_i;
|
logic [15:0] sw_i;
|
||||||
logic tb_rx;
|
logic tb_rx;
|
||||||
logic flashing_is_done = 0;
|
logic flashing_is_done = 0;
|
||||||
logic core_reset;
|
logic core_reset;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ OBJCOPY = $(CC_PATH)/$(CC_PREFIX)-objcopy
|
|||||||
SIZE = $(CC_PATH)/$(CC_PREFIX)-size
|
SIZE = $(CC_PATH)/$(CC_PREFIX)-size
|
||||||
|
|
||||||
OBJS = core_main.o core_list_join.o core_matrix.o core_state.o core_util.o \
|
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
|
barebones/ee_printf.o
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ endmodule
|
|||||||
module testbench();
|
module testbench();
|
||||||
logic A, B, C;
|
logic A, B, C;
|
||||||
|
|
||||||
adder DUT(
|
half_adder DUT(
|
||||||
.A(A), // <- здесь будет ошибка,
|
.A(A), // <- здесь будет ошибка,
|
||||||
// т.к. в модуле half_adder нет порта 'A'
|
// т.к. в модуле half_adder нет порта 'A'
|
||||||
.b(B),
|
.b(B),
|
||||||
|
|||||||