Compare commits
19 Commits
7ebed1ded9
...
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]
|
||||
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
@@ -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
|
||||
set -e
|
||||
|
||||
mkdir src
|
||||
mkdir -p src
|
||||
cp .github/book.toml .github/*.md ./
|
||||
|
||||
# Copy custom theme assets (language switcher, etc.)
|
||||
if [ -d ".github/theme" ]; then
|
||||
cp -r .github/theme ./
|
||||
fi
|
||||
|
||||
44
.github/theme/language-switcher.css
vendored
Normal file
@@ -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();
|
||||
}
|
||||
})();
|
||||
83
.github/workflows/mdbook.yml
vendored
@@ -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:
|
||||
|
||||
|
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();
|
||||
logic A, B, C;
|
||||
|
||||
adder DUT(
|
||||
half_adder DUT(
|
||||
.A(A), // <- здесь будет ошибка,
|
||||
// т.к. в модуле half_adder нет порта 'A'
|
||||
.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`.
|
||||
|
||||
<details>
|
||||
|
||||
@@ -79,7 +79,7 @@ _Рисунок 4. УГО логического вентиля **НЕ**._
|
||||
|
||||
Также существуют вариации базовых вентилей, такие как **И-НЕ**, **ИЛИ-НЕ**, **Исключающее ИЛИ-НЕ**, отличающиеся от исходных тем, что результат операции инвертирован относительно результата аналогичной операции без **-НЕ**.
|
||||
|
||||
Логические вентили строятся из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
|
||||
Логические вентили могут быть построены из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
|
||||
|
||||
Особенностью современных интегральных схем является то, что они строятся на основе комплементарной (взаимодополняющей) пары транзисторов **P** и **N**-типа (**Комплементарная Металл-Оксид-Полупроводниковая**, **КМОП** логика). Для данного типа транзисторов оказалось эффективнее реализовать операции **И-НЕ** и **ИЛИ-НЕ**.
|
||||
|
||||
|
||||
@@ -78,6 +78,6 @@ endmodule
|
||||
|
||||
1. [Intel 4004 — 50th Anniversary Project](https://www.4004.com/mcs4-masks-schematics-sim.html);
|
||||
2. [Страница википедии по Intel 4004](https://en.wikipedia.org/wiki/Intel_4004);
|
||||
3. [F.Ka˘gan. Gürkaynak / Side Channel Attack Secure Cryptographic Accelerators](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf);
|
||||
4. [FIPS 197, Advanced Encryption Standart (AES)](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf);
|
||||
3. [F.Kağan. Gürkaynak / Side Channel Attack Secure Cryptographic Accelerators](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf);
|
||||
4. [FIPS 197, Advanced Encryption Standard (AES)](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf);
|
||||
5. [P. Flake, P. Moorby, S. Golson, A. Salz, S. Davidmann / Verilog HDL and Its Ancestors and Descendants](https://dl.acm.org/doi/pdf/10.1145/3386337).
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
- способами описания [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) на языке SystemVerilog.
|
||||
|
||||
## Общий ход выполнения работы
|
||||
## Ход работы
|
||||
|
||||
1. Изучить устройство и принцип работы АЛУ (раздел [#теория](#Теория))
|
||||
2. Изучить языковые конструкции SystemVerilog для реализации АЛУ (раздел [#инструменты](#Инструменты))
|
||||
|
||||
@@ -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. Сигнала управления мультиплексором, выбирающим слагаемое для программного счётчика
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. Данная лабораторная работа не предполагает проверки в ПЛИС
|
||||
|
||||
@@ -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, однако теперь появляется:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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. Данная лабораторная работа не предполагает проверки в ПЛИС.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
1. Описать модуль контроллера прерываний.
|
||||
2. Описать модуль контроллера регистров статуса и контроля (**CSR**-контроллер).
|
||||
|
||||
## Ход выполнения
|
||||
## Ход работы
|
||||
|
||||
1. Изучение теории по прерываниям и исключениям в архитектуре RISC-V, включая работу с регистрами статуса и контроля (**CSR**) и механизмы реализации прерываний.
|
||||
2. Реализация схемы обработки прерывания для устройства на основе RISC-V
|
||||
@@ -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)
|
||||
# что означает возврат в бесконечный цикл
|
||||
```
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -82,7 +82,7 @@ irq_o_is_not_0: assert property (
|
||||
irq_cause_o_mcause: assert property (
|
||||
@(posedge clk_i) disable iff ( rst_i )
|
||||
irq_o |-> $onehot0(irq_cause_o[19:4])
|
||||
)else $error("error value on irq_cause_o: %08h, should be onehot", $sampled(irq_cause_o[20:5]));
|
||||
)else $error("error value on irq_cause_o: %08h, should be onehot", $sampled(irq_cause_o[19:4]));
|
||||
|
||||
irq_cause_o_borders: assert property (
|
||||
@(posedge clk_i) disable iff ( rst_i )
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ endmodule
|
||||
module testbench();
|
||||
logic A, B, C;
|
||||
|
||||
adder DUT(
|
||||
half_adder DUT(
|
||||
.A(A), // <- здесь будет ошибка,
|
||||
// т.к. в модуле half_adder нет порта 'A'
|
||||
.b(B),
|
||||
|
||||