feat: add lab-rv32i-c-interrupts card
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
build/
|
||||
doc/generated/*.aux
|
||||
doc/generated/*.fdb_latexmk
|
||||
doc/generated/*.fls
|
||||
doc/generated/*.log
|
||||
doc/generated/*.out
|
||||
doc/generated/*.pdf
|
||||
doc/generated/*.upa
|
||||
@@ -0,0 +1,54 @@
|
||||
RISCV_PREFIX ?= riscv64-unknown-elf-
|
||||
CC := $(RISCV_PREFIX)gcc
|
||||
OBJCOPY := $(RISCV_PREFIX)objcopy
|
||||
OBJDUMP := $(RISCV_PREFIX)objdump
|
||||
SIZE := $(RISCV_PREFIX)size
|
||||
|
||||
RV_ENV_ROOT ?= /home/user/dev/edu/rv32i-hazard3-student-env
|
||||
H3_COMMON ?= $(RV_ENV_ROOT)/vendor/Hazard3/test/sim/common
|
||||
H3_INIT ?= $(H3_COMMON)/init.S
|
||||
LDSCRIPT ?= link/hazard3_c10.ld
|
||||
MEMOPS ?= $(RV_ENV_ROOT)/vendor/lab-runtime/memops.c
|
||||
|
||||
BUILD_ROOT ?= build
|
||||
TASKS := task01_ecall_resume task02_machine_software_irq task03_pending_enable_matrix
|
||||
ARCH ?= rv32i_zicsr_zifencei
|
||||
ABI ?= ilp32
|
||||
CFLAGS := -std=gnu11 -march=$(ARCH) -mabi=$(ABI) -nostdlib -nostartfiles \
|
||||
-ffreestanding -fno-builtin -fno-stack-protector -fno-pic -mno-relax \
|
||||
-O0 -g3 -Wall -Wextra -Isrc/tasks -isystem $(H3_COMMON)
|
||||
LDFLAGS := -Wl,--no-relax -T$(LDSCRIPT)
|
||||
LIBS := -lgcc
|
||||
|
||||
.PHONY: all tasks check clean task1 task2 task3
|
||||
all: tasks
|
||||
tasks: $(TASKS)
|
||||
task1: $(word 1,$(TASKS))
|
||||
task2: $(word 2,$(TASKS))
|
||||
task3: $(word 3,$(TASKS))
|
||||
|
||||
check:
|
||||
@test -f "$(H3_INIT)"
|
||||
@test -f "$(LDSCRIPT)"
|
||||
@test -f "$(MEMOPS)"
|
||||
|
||||
define TASK_RULES
|
||||
$(1): $(BUILD_ROOT)/$(1)/prog.bin $(BUILD_ROOT)/$(1)/prog.lst
|
||||
|
||||
$(BUILD_ROOT)/$(1)/prog.elf: crt0.S src/tasks/$(1).c src/tasks/c10_common.h $(H3_INIT) $(LDSCRIPT) $(MEMOPS) | check
|
||||
mkdir -p $$(@D)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$(BUILD_ROOT)/$(1)/prog.map \
|
||||
-o $$@ $(H3_INIT) crt0.S $(MEMOPS) src/tasks/$(1).c $(LIBS)
|
||||
$(SIZE) -A -x $$@
|
||||
|
||||
$(BUILD_ROOT)/$(1)/prog.bin: $(BUILD_ROOT)/$(1)/prog.elf
|
||||
$(OBJCOPY) -O binary $$< $$@
|
||||
|
||||
$(BUILD_ROOT)/$(1)/prog.lst: $(BUILD_ROOT)/$(1)/prog.elf
|
||||
$(OBJDUMP) -d -S -M no-aliases,numeric $$< > $$@
|
||||
endef
|
||||
|
||||
$(foreach task,$(TASKS),$(eval $(call TASK_RULES,$(task))))
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_ROOT)
|
||||
@@ -0,0 +1,18 @@
|
||||
# C10 — pułapki i sterowanie przerwaniami RV32I
|
||||
|
||||
Trzy obrazy pokazują kolejno:
|
||||
|
||||
1. synchroniczny `ecall`, `mepc + 4` i wznowienie przez `mret`;
|
||||
2. machine software interrupt z kontrolowanym pending;
|
||||
3. macierz: źródło pending, `mie.MSIE` i `mstatus.MIE`.
|
||||
|
||||
`set_softirq` jest kontrolowanym źródłem testbench, dzięki czemu karta nie
|
||||
miesza jeszcze sterownika peryferium z mechanizmem pułapki. C12 i C13 dodają
|
||||
UART i GPIO jako rzeczywiste źródła external IRQ modelu.
|
||||
|
||||
```bash
|
||||
make tasks
|
||||
./tests/test_hazard3.sh
|
||||
./scripts/render_card_layouts.sh
|
||||
GITEA_SHA=0000000000000000000000000000000000000000 ./scripts/render_new_pdf.sh
|
||||
```
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
|
||||
_start:
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
|
||||
la a0, __bss_start
|
||||
la a1, __bss_end
|
||||
1:
|
||||
bgeu a0, a1, 2f
|
||||
sb zero, 0(a0)
|
||||
addi a0, a0, 1
|
||||
j 1b
|
||||
2:
|
||||
call main
|
||||
tail _exit
|
||||
|
||||
.size _start, .-_start
|
||||
@@ -0,0 +1,472 @@
|
||||
% Generated from json/card_source.json by tools/render_card.py.
|
||||
% Do not edit manually; update the JSON and regenerate.
|
||||
|
||||
\documentclass[12pt,a4paper]{article}
|
||||
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{lmodern}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[polish]{babel}
|
||||
\usepackage{csquotes}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{xcolor}
|
||||
\usepackage[a4paper,left=2.15cm,right=2.15cm,top=0.5cm,bottom=0.5cm,headheight=24mm,headsep=3mm,includehead]{geometry}
|
||||
\usepackage{eso-pic}
|
||||
\usepackage{marginnote}
|
||||
\usepackage{array}
|
||||
\usepackage{tabularx}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{float}
|
||||
\usepackage{silence}
|
||||
\WarningFilter{soulutf8}{This package is obsolete}
|
||||
\usepackage{pdfcomment}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{needspace}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{lastpage}
|
||||
\usepackage{microtype}
|
||||
\usepackage[most]{tcolorbox}
|
||||
\usepackage{qrcode}
|
||||
\IfFileExists{references.bib}{%
|
||||
\usepackage[backend=biber,style=numeric,sorting=none]{biblatex}%
|
||||
\addbibresource{references.bib}%
|
||||
}{}
|
||||
|
||||
\hypersetup{hidelinks}
|
||||
|
||||
\IfFileExists{build-meta.tex}{%
|
||||
\input{build-meta.tex}%
|
||||
}{%
|
||||
\newcommand{\BuildCommit}{lokalna}%
|
||||
}
|
||||
|
||||
\newcommand{\DocumentAuthor}{M. Pabiszczak}
|
||||
\newcommand{\DocumentYear}{2026}
|
||||
\newcommand{\CardSeries}{c}
|
||||
\newcommand{\CardNumber}{10}
|
||||
\newcommand{\CardCount}{13}
|
||||
\newcommand{\CardSlug}{traps-interrupt-control}
|
||||
\newcommand{\CardVersion}{v00.01}
|
||||
\newcommand{\DocumentUUID}{ec04ecee-1c4d-529a-a4e2-d3f9b40700ec}
|
||||
|
||||
\newcommand{\EmptyCheck}{\(\square\)}
|
||||
\newcommand{\EscAnswerLines}[1][3]{\par\noindent\dotfill\par\noindent\dotfill\par\noindent\dotfill}
|
||||
\newcommand{\EscWriteRow}[1][2.8em]{\rule{0pt}{#1}}
|
||||
\setlength{\parindent}{0pt}
|
||||
\setlength{\parskip}{0.45em}
|
||||
\setlength{\headheight}{24mm}
|
||||
\setlength{\headsep}{3mm}
|
||||
\setlength{\footskip}{8mm}
|
||||
\setlength{\marginparwidth}{1.5cm}
|
||||
\setlength{\marginparsep}{0.25cm}
|
||||
\renewcommand{\arraystretch}{1.22}
|
||||
% Margin separator lines disabled for layout trial.
|
||||
|
||||
\newcommand{\ESCPageResourceHeader}{%
|
||||
\begingroup%
|
||||
\setlength{\parskip}{0pt}%
|
||||
\setlength{\fboxsep}{0pt}%
|
||||
\setlength{\fboxrule}{0.35pt}%
|
||||
\setlength{\arrayrulewidth}{0.35pt}%
|
||||
\noindent\fbox{%
|
||||
\begin{minipage}[c][23.5mm][c]{\dimexpr\textwidth-2\fboxrule\relax}%
|
||||
\begin{minipage}[c][23mm][c]{24mm}\centering%
|
||||
\href{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-interrupts}{\qrcode[level=L,height=22mm]{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-interrupts}}%
|
||||
\end{minipage}%
|
||||
\vrule width0.35pt%
|
||||
\begin{minipage}[c][23mm][c]{\dimexpr\linewidth-48mm-0.7pt\relax}%
|
||||
\setlength{\tabcolsep}{0pt}%
|
||||
\renewcommand{\arraystretch}{0}%
|
||||
\begin{tabularx}{\linewidth}{@{}p{\dimexpr0.50000000\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.15126050\linewidth-\arrayrulewidth\relax}|X@{}}%
|
||||
\parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries TITLE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{7.7}{7.9}\selectfont\ttfamily\bfseries Pułapki i sterowanie przerwaniami RV32I}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries VER.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.6}{6.8}\selectfont\ttfamily\bfseries v00.01}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries DATETIME}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries 2026-07-20T00:00:00+02:00}\hspace{0.45mm}}\par} \\%
|
||||
\end{tabularx}%
|
||||
\par\nointerlineskip%
|
||||
\hrule height0.35pt%
|
||||
\nointerlineskip%
|
||||
\begin{tabularx}{\linewidth}{@{}p{\dimexpr0.50000000\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.25210084\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.14285714\linewidth-\arrayrulewidth\relax}|X@{}}%
|
||||
\parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries PROJECT}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{7.7}{7.9}\selectfont\ttfamily\bfseries Freestanding C na RV32I}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries SERIES}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries C · Freestanding RV32I and K\&R}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries CARD}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries 10/13}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries SHEET}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries \thepage/\pageref{LastPage}}\hspace{0.45mm}}\par} \\%
|
||||
\end{tabularx}%
|
||||
\par\nointerlineskip%
|
||||
\hrule height0.35pt%
|
||||
\nointerlineskip%
|
||||
\begin{tabularx}{\linewidth}{@{}p{\dimexpr0.05882353\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.05042017\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.14705882\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.09243697\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.07563025\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.07563025\linewidth-\arrayrulewidth\relax}|X@{}}%
|
||||
\parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries SUBJ.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries Inf.}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries PROG.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries CORE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries SCOPE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries LEVEL}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries POS.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hbox to\linewidth{\hspace{0.35mm}{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries GITEA UUID}\hfill{\fontsize{3.4}{3.75}\selectfont\ttfamily ec04ecee-1c4d-529a-a4e2-d3f9b40700ec}\hspace{0.35mm}}\par\nointerlineskip\hbox to\linewidth{\hspace{0.35mm}{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries CARD UUID} {\fontsize{3.4}{3.75}\selectfont\ttfamily 8fb9c110-557b-5081-8ae2-a56800f872e8}\hfill{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries AUTHOR M. Pabiszczak}\hspace{0.35mm}}} \\%
|
||||
\end{tabularx}%
|
||||
\par\nointerlineskip%
|
||||
\hrule height0.35pt%
|
||||
\nointerlineskip%
|
||||
\begin{tabularx}{\linewidth}{@{}X@{}}%
|
||||
\parbox[c][3.46276mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{4.5}{4.85}\selectfont\ttfamily\bfseries GITEA} {\fontsize{4.5}{4.85}\selectfont\ttfamily\href{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-interrupts}{\nolinkurl{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-interrupts}}}} \\%
|
||||
\end{tabularx}%
|
||||
\par\nointerlineskip%
|
||||
\hrule height0.35pt%
|
||||
\nointerlineskip%
|
||||
\begin{tabularx}{\linewidth}{@{}X@{}}%
|
||||
\parbox[c][3.46276mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{4.5}{4.85}\selectfont\ttfamily\bfseries HTML} {\fontsize{4.5}{4.85}\selectfont\ttfamily\href{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8fb9c110-557b-5081-8ae2-a56800f872e8}{\nolinkurl{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8fb9c110-557b-5081-8ae2-a56800f872e8}}}} \\%
|
||||
\end{tabularx}%
|
||||
\end{minipage}%
|
||||
\vrule width0.35pt%
|
||||
\begin{minipage}[c][23mm][c]{24mm}\centering%
|
||||
\href{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8fb9c110-557b-5081-8ae2-a56800f872e8}{\qrcode[level=L,height=22mm]{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8fb9c110-557b-5081-8ae2-a56800f872e8}}%
|
||||
\end{minipage}%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\endgroup%
|
||||
}
|
||||
|
||||
\pagestyle{fancy}
|
||||
\fancyhf{}
|
||||
\fancyhead[C]{\ESCPageResourceHeader}
|
||||
\renewcommand{\headrulewidth}{0pt}
|
||||
\renewcommand{\footrulewidth}{0pt}
|
||||
|
||||
\newcommand{\ESCMarginTag}[4]{%
|
||||
\hspace*{#1}\textcolor{#2}{#3~#4}%
|
||||
}
|
||||
\newcommand{\ESCSectionBlockStart}{%
|
||||
\Needspace{8\baselineskip}%
|
||||
\par\vspace{0.35em}%
|
||||
\noindent\textcolor{black!28}{\rule{\textwidth}{0.35pt}}%
|
||||
\par\vspace{0.15em}%
|
||||
}
|
||||
\newcommand{\ESCSectionBlockEnd}{%
|
||||
\par\vspace{0.45em}%
|
||||
}
|
||||
\newcommand{\ESCTinyStepSeparator}{%
|
||||
\par\vspace{0.10em}%
|
||||
\noindent{\color{black!18}\leaders\hbox{\rule{0.60em}{0.22pt}\hspace{0.38em}}\hfill\kern0pt}%
|
||||
\par\vspace{0.10em}%
|
||||
}
|
||||
\newtcolorbox{ESCTaskFrame}[1]{enhanced,breakable,arc=0pt,boxrule=0.35pt,colback=white,colframe=black,boxsep=0pt,left=1.4mm,right=1.4mm,top=0.8mm,bottom=0.8mm,colbacktitle=black!7,coltitle=black,title={\ttfamily\bfseries TASK\quad #1}}
|
||||
\newtcolorbox{ESCBlockFrame}[1]{enhanced,breakable,arc=0pt,boxrule=0.35pt,colback=white,colframe=black!55,boxsep=0pt,left=1.0mm,right=1.0mm,top=0.6mm,bottom=0.6mm,colbacktitle=black!4,coltitle=black,title={\ttfamily\bfseries BLOCK\quad #1}}
|
||||
\newtcolorbox{ESCStepFrame}[1]{enhanced,breakable,arc=0pt,boxrule=0.35pt,colback=white,colframe=black!28,boxsep=0pt,left=0.8mm,right=0.8mm,top=0.45mm,bottom=0.45mm,colbacktitle=black!2,coltitle=black,title={\ttfamily STEP\quad #1}}
|
||||
\newtcolorbox{ESCConclusionFrame}{enhanced,breakable,arc=0pt,boxrule=0.45pt,colback=blue!2,colframe=blue!45!black,boxsep=0pt,left=1.2mm,right=1.2mm,top=0.7mm,bottom=0.7mm,colbacktitle=blue!7,coltitle=black,title={\ttfamily\bfseries WNIOSEK}}
|
||||
|
||||
\newcommand{\ESCLearningTreeWidget}{%
|
||||
\reversemarginpar
|
||||
\marginnote[%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\begin{minipage}[t]{\marginparwidth}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{TECH}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\hspace*{0.28em}\textcolor{orange!85!black}{EK~LOCAL~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Uczeń uruchamia trzy obrazy Hazard3 i wiąże raporty runtime z instrukcjami ecall, CSR,\textCR wektorami i mret.}}\par%
|
||||
\hspace*{0.54em}\textcolor{blue!70!black}{KW~LOCAL~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Kod, przewidywanie i pomiar tworzą jeden dowód.}}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
]{}
|
||||
\normalmarginpar
|
||||
|
||||
\marginnote{%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\hspace*{0.06cm}%
|
||||
\begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{OG}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\hspace*{0.28em}\textcolor{green!50!black}{EN~LOCAL~EN~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Uczeń osobno zapisuje źródło zdarzenia, mcause, mepc, stan pending, obie bramki enable i\textCR efekt po mret.}}\par%
|
||||
\hspace*{0.54em}\textcolor{blue!70!black}{KW~LOCAL~KW~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Kod, przewidywanie i pomiar tworzą jeden dowód.}}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
\begin{document}
|
||||
\sloppy
|
||||
|
||||
\vspace{1.0em}
|
||||
\noindent{\Large\bfseries Cel karty}\par
|
||||
\vspace{0.35em}
|
||||
Uczeń odróżnia synchroniczny wyjątek od asynchronicznego przerwania, wyprowadza adres wznowienia z mepc oraz dowodzi, że samo pending nie wystarcza bez indywidualnej i globalnej bramki enable.
|
||||
|
||||
\vspace{0.8em}
|
||||
\noindent\textcolor{black!25}{\rule{\textwidth}{0.35pt}}
|
||||
\vspace{0.7em}
|
||||
\noindent{\Large\bfseries Zakres i zachowane przykłady}\par
|
||||
\vspace{0.35em}
|
||||
Trzy obrazy RV32I działają na rzeczywistym modelu Hazard3. Task01 wykonuje \texttt{ecall}; Task02 używa kontrolowanego machine software interrupt; Task03 mierzy macierz pending, \texttt{mie.MSIE} i \texttt{mstatus.MIE}. Peryferia pojawiają się dopiero w C12 i C13.\par\textbf{Układ każdego przykładu:} pełny profil A1--A8; widok N/D ma jawny powód, a diagram nie jest wymagany, gdy tekst daje lepszy dowód.
|
||||
\vspace{0.55em}
|
||||
\small\begin{tabularx}{\textwidth}{@{}>{\ttfamily\raggedright\arraybackslash}p{1.10cm}>{\ttfamily\raggedright\arraybackslash}p{1.45cm}X>{\raggedright\arraybackslash}p{2.50cm}@{}}
|
||||
\textbf{Typ} & \textbf{Task} & \textbf{Idea} & \textbf{Waga} \\ \hline
|
||||
\hline
|
||||
\textbf{\texttt{ECALL}} & \textbf{\texttt{Task01}} & \textbf{synchroniczny cause 11, mepc i mret} & \textbf{kluczowe} \\ \hline
|
||||
\hline
|
||||
\textbf{\texttt{MSIP}} & \textbf{\texttt{Task02}} & \textbf{MSIP, MSIE, MIE, vector 3 i mret} & \textbf{kluczowe} \\ \hline
|
||||
\hline
|
||||
\textbf{\texttt{GATE}} & \textbf{\texttt{Task03}} & \textbf{to samo źródło, dwie niezależne bramki} & \textbf{kluczowe} \\ \hline
|
||||
\end{tabularx}
|
||||
\normalsize
|
||||
|
||||
|
||||
\vspace{0.8em}
|
||||
\noindent\textcolor{black!25}{\rule{\textwidth}{0.35pt}}
|
||||
|
||||
\clearpage
|
||||
|
||||
\ESCSectionBlockStart
|
||||
\section{1 — Wyjątek synchroniczny wskazuje instrukcję}
|
||||
\reversemarginpar
|
||||
\marginnote[%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\begin{minipage}[t]{\marginparwidth}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{TECH}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
]{}[-3.1em]
|
||||
\normalmarginpar
|
||||
|
||||
\marginnote{%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\hspace*{0.06cm}%
|
||||
\begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{OG}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
}[-3.1em]
|
||||
|
||||
|
||||
\texttt{ecall} jest wykonywany przez bieżący strumień instrukcji, więc \texttt{mcause=11} nie ma ustawionego bitu interrupt, a \texttt{mepc} wskazuje samo \texttt{ecall}. Handler Task01 świadomie zapisuje \texttt{mepc+4}; bez tego \texttt{mret} wykonałby ponownie tę samą instrukcję. Taka polityka jest poprawna dla tego kontrolowanego ECALL, ale nie wolno automatycznie pomijać instrukcji przy każdym błędzie.
|
||||
\ESCSectionBlockEnd
|
||||
|
||||
\ESCSectionBlockStart
|
||||
\section{2 — Software IRQ jest asynchronicznym źródłem poziomowym}
|
||||
\reversemarginpar
|
||||
\marginnote[%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\begin{minipage}[t]{\marginparwidth}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{TECH}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
]{}[-3.1em]
|
||||
\normalmarginpar
|
||||
|
||||
\marginnote{%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\hspace*{0.06cm}%
|
||||
\begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{OG}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
}[-3.1em]
|
||||
|
||||
|
||||
Testbench ustawia MSIP hart0, a rdzeń widzi \texttt{mip.MSIP}. Dostarczenie wymaga dodatkowo \texttt{mie.MSIE=1} i \texttt{mstatus.MIE=1}. Wektor 3 prowadzi do \texttt{isr\_machine\_softirq}; handler odczytuje \texttt{mcause=0x80000003}, usuwa źródło i dopiero potem publikuje licznik. \texttt{mret} wraca do przerwanego kodu, a nie do instrukcji wybranej ręcznie przez aplikację.
|
||||
\ESCSectionBlockEnd
|
||||
|
||||
\ESCSectionBlockStart
|
||||
\section{3 — Pending i enable odpowiadają na inne pytania}
|
||||
\reversemarginpar
|
||||
\marginnote[%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\begin{minipage}[t]{\marginparwidth}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{TECH}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
]{}[-3.1em]
|
||||
\normalmarginpar
|
||||
|
||||
\marginnote{%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\hspace*{0.06cm}%
|
||||
\begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{OG}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
}[-3.1em]
|
||||
|
||||
|
||||
Pending mówi, że źródło żąda obsługi. \texttt{mie.MSIE} dopuszcza konkretną klasę, a \texttt{mstatus.MIE} otwiera globalną bramkę machine mode. Task03 utrzymuje to samo pending i kolejno sprawdza dwa stany z jedną zamkniętą bramką oraz stan z obiema otwartymi. Dzięki temu kod 0 dowodzi całej macierzy, a nie tylko tego, że ISR kiedyś się wykonał.
|
||||
\ESCSectionBlockEnd
|
||||
|
||||
\clearpage
|
||||
\ESCSectionBlockStart
|
||||
\section{Zadania — zachowane przykłady w profilu A1–A8}
|
||||
\reversemarginpar
|
||||
\marginnote[%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\begin{minipage}[t]{\marginparwidth}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{TECH}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
]{}[-3.1em]
|
||||
\normalmarginpar
|
||||
|
||||
\marginnote{%
|
||||
\begin{minipage}{\marginparwidth}%
|
||||
\raggedright
|
||||
{\fontsize{3.55}{3.95}\selectfont\ttfamily
|
||||
\hspace*{0.06cm}%
|
||||
\begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}%
|
||||
\raggedright
|
||||
{\bfseries\textcolor{black!65}{OG}\par}%
|
||||
\vspace{0.08em}%
|
||||
\hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par%
|
||||
\end{minipage}%
|
||||
}%
|
||||
\end{minipage}%
|
||||
}[-3.1em]
|
||||
|
||||
|
||||
\begin{ESCTaskFrame}{TASK01 · ECALL i wznowienie pod mepc+4}
|
||||
{\scriptsize\ttfamily 2cd1da12-b916-5def-b868-da4b13ff9089}\par
|
||||
\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — kontrolowany wyjątek M-mode}
|
||||
\textbf{Zachowany przykład:} \nolinkurl{src/tasks/task01_ecall_resume.c}.\par Granica zaczyna się na instrukcji \texttt{ecall} w main i kończy po powrocie do kolejnej instrukcji. Nie ma zewnętrznego peryferium ani pending IRQ; rdzeń sam tworzy synchroniczną pułapkę.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — mcause, mepc i mtvec}
|
||||
\texttt{mcause} zapisuje klasę 11 bez bitu interrupt, \texttt{mepc} zapisuje adres ECALL, a baza \texttt{mtvec} prowadzi wszystkie synchroniczne wyjątki do \texttt{handle\_exception}. Handler publikuje oryginał i osobny adres wznowienia.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A3 DISPATCH · AKTYWNE — synchroniczny slot mtvec}
|
||||
Sprzęt wybiera bazowy slot wektora, ponieważ zdarzenie jest wyjątkiem, nie IRQ. \texttt{handle\_exception} odczytuje mcause i obsługuje jedyny dopuszczony przypadek ECALL. To granica trap dispatch, choć nie ma tablicy callbacków.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — cause 11 i stały krok 4}
|
||||
ECALL w RV32I jest instrukcją 32-bitową, dlatego dla tego przykładu poprawny resume ma wartość \texttt{mepc+4}. Gate wymaga jednego wejścia, cause 11, delty 4 i ustawienia resumed dopiero po mret.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — ecall, save, patch, mret}
|
||||
Normalny kod wykonuje ECALL. Rdzeń zapisuje mepc/mcause, skacze do wektora, handler odczytuje oba CSR i zapisuje nowe mepc. Epilog \texttt{interrupt("machine")} kończy się mret; dopiero potem main zapisuje resumed.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — RUNNING, TRAP, RESUMED}
|
||||
Stan przechodzi \texttt{RUNNING -> TRAP(mepc=ecall,cause=11) -> RESUMED(pc=mepc+4)}. Licznik 1 odróżnia pojedyncze wznowienie od pętli ponownego wykonywania ECALL.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — ecall i mret w ELF}
|
||||
Oracle porównuje raportowane adresy i niezależnie wymaga różnicy 4. Objdump musi pokazać \texttt{ecall} w main oraz \texttt{mret} w handlerze. Segmenty LOAD pozostają rozdzielone R-X/R-W.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — explicit resume policy}
|
||||
Wzorzec handlera wyjątku obejmuje jawną decyzję: retry, skip albo terminate. Task01 wybiera skip tylko dla znanego ECALL. Dla faultu pamięci bezwarunkowe mepc+4 mogłoby ukryć błąd i jest niedozwolone.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek}
|
||||
Przed uruchomieniem przewidź bit interrupt i kod mcause, wskaż wartość mepc oraz adres wznowienia. Wyjaśnij, co stałoby się bez zapisu mepc+4.
|
||||
\par\textbf{Evidence:} Adres ecall i dwa adresy mepc z raportu/listingu, cause 11, instrukcja mret oraz kod wyjścia Hazard3.
|
||||
\par\textbf{Acceptance:} Hazard3: count=1, mcause=0x0000000b, resume\_pc-mepc=4, resumed=1, pass=1 i kod 0.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{TASK01 · Zapis dowodu ucznia}
|
||||
\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. mcause, mepc i adres wznowienia}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. ecall/mret w listingu i kod wyjścia}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill
|
||||
\end{ESCBlockFrame}
|
||||
\end{ESCTaskFrame}
|
||||
\clearpage
|
||||
\begin{ESCTaskFrame}{TASK02 · Machine software IRQ i clear źródła}
|
||||
{\scriptsize\ttfamily a4b503ba-cacc-5af1-9ecd-31f51563ca76}\par
|
||||
\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — kontrolowane źródło bez peryferium}
|
||||
\textbf{Zachowany przykład:} \nolinkurl{src/tasks/task02_machine_software_irq.c}.\par \texttt{tb\_set\_softirq(0)} podnosi machine software interrupt hart0. Testbench jest źródłem, CSR są kontrolą rdzenia, ISR usuwa żądanie, a main ocenia wznowienie. UART/GPIO nie uczestniczą.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — trzy bity i jeden wektor}
|
||||
Źródło jest widoczne jako \texttt{mip.MSIP}; indywidualna bramka to \texttt{mie.MSIE}, globalna to \texttt{mstatus.MIE}. Cause 3 w trybie vectored wybiera slot 3 i symbol \texttt{isr\_machine\_softirq}.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A3 DISPATCH · AKTYWNE — sprzęt wybiera vector 3}
|
||||
Bit interrupt w mcause i kod 3 powodują sprzętowy wybór slotu machine software IRQ. Nie jest to statyczne jal z main. Po wejściu symbol handlera jest już określony przez wektor, a mret odtwarza przerwany kontekst.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — pending 1 do 0}
|
||||
Przy MSIE=1 i MIE=0 źródło jest już pending, lecz licznik wynosi 0. Po otwarciu MIE handler widzi \texttt{0x80000003} i pending=1, wykonuje clear, zwiększa licznik, a po mret main mierzy pending=0.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — configure, assert, observe, enable}
|
||||
Kolejność eliminuje wyścig pomiaru: najpierw wyłącz wszystko, ustaw MSIE, podnieś źródło, zmierz pending, dopiero potem ustaw MIE. Handler odczytuje cause/pending przed clear i publikuje licznik po clear.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — MASKED\_PENDING, ACTIVE, CLEARED}
|
||||
Źródło przechodzi do \texttt{MASKED\_PENDING}, bo globalna bramka jest zamknięta. Po MIE staje się ACTIVE; clear w ISR tworzy CLEARED. Resumed=1 jest osobnym stanem normalnego kodu po mret.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — cause z bitem 31}
|
||||
Wartość \texttt{0x80000003} łączy bit interrupt i kod 3. Listing ma pokazać CSR dla mie/mstatus/mip, dostęp do testbench clear oraz mret. Oracle wymaga całego śladu, nie tylko pass.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — clear level source before publish}
|
||||
Źródło poziomowe usuwa się przed opublikowaniem ukończenia ISR. Gdyby licznik wzrósł bez clear, po mret żądanie pozostałoby aktywne i handler mógłby wejść ponownie.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek}
|
||||
Zapisz stan pending przed globalnym enable, mcause w ISR i pending po clear. Rozdziel źródło MSIP od obu bramek oraz wskaż, dlaczego handler musi usunąć źródło przed mret.
|
||||
\par\textbf{Evidence:} Ślad źródło→pending→MSIE/MIE→vector 3→ISR→clear→mret, raport globali i kod wyjścia Hazard3.
|
||||
\par\textbf{Acceptance:} Hazard3: count=1, mcause=0x80000003, pending\_before=1, pending\_in\_handler=1, pending\_after=0, resumed=1, pass=1 i kod 0.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{TASK02 · Zapis dowodu ucznia}
|
||||
\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Pending i bramki przed wejściem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. mcause, clear, mret i wznowienie}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill
|
||||
\end{ESCBlockFrame}
|
||||
\end{ESCTaskFrame}
|
||||
\clearpage
|
||||
\begin{ESCTaskFrame}{TASK03 · Macierz pending, MSIE i MIE}
|
||||
{\scriptsize\ttfamily f56dba83-f7a9-5643-8f2e-84df1e8a2190}\par
|
||||
\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — jedna zmienna, dwie kontrolki}
|
||||
\textbf{Zachowany przykład:} \nolinkurl{src/tasks/task03_pending_enable_matrix.c}.\par Bodziec MSIP pozostaje ten sam podczas dwóch prób blokowanych i próby dostarczonej. Przykład zmienia wyłącznie bramki rdzenia, więc nie myli nowego zdarzenia z nową konfiguracją.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — macierz 1×2×2}
|
||||
Oś danych to pending=1. Dwie osie sterujące to MSIE i MIE. Cztery kombinacje mają jeden stan dostarczalny: oba bity 1. Przykład mierzy trzy istotne wiersze przy utrzymanym pending.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A3 DISPATCH · AKTYWNE — wejście dopiero dla 1/1}
|
||||
Sprzętowy dispatch do vector 3 nie zachodzi przy żadnej pojedynczej otwartej bramce. Dopiero MSIE=1 i MIE=1 pozwalają utworzyć trap, zapisać cause i wejść do ISR kończącego się mret.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — dwa razy blocked, raz delivered}
|
||||
Przy MIE=1/MSIE=0 licznik zostaje 0. Przy MIE=0/MSIE=1 również zostaje 0. Przy obu równych 1 rośnie dokładnie do 1, mcause ma wartość 0x80000003, a clear zeruje pending.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — nie zmieniaj źródła między próbami}
|
||||
Program podnosi MSIP raz, następnie testuje global-only, individual-only i both. Globalny bit jest zamykany przed zmianą MSIE, aby dostarczenie nie zaszło między pomiarem a zapisaniem wyniku.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — P10, P01, P11, CLEAR}
|
||||
Skrót \texttt{Pxy} oznacza pending=1, MSIE=x, MIE=y. Ślad to \texttt{P01(blocked) -> P10(blocked) -> P11(active) -> CLEAR}. Licznik zmienia się tylko na trzeciej krawędzi.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — odczyt mip, zapisy mie/mstatus}
|
||||
Raport utrwala trzy decyzje i cause. Listing rozdziela \texttt{csrs/csrc mie}, \texttt{csrs/csrc mstatus} oraz odczyt mip. Objdump niezależnie potwierdza mret w ISR.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — source, individual, global gate}
|
||||
Trzywarstwowy model zapobiega typowemu błędowi: pending nie znaczy delivered. Ten sam wzorzec wróci dla MTIP/MTIE oraz external IRQ z enable peryferium, kontrolera i globalnym MIE.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek}
|
||||
Wypełnij trzy wiersze: pending=1 z samym MIE, pending=1 z samym MSIE oraz pending=1 z obiema bramkami. Przewidź licznik ISR i końcowy pending.
|
||||
\par\textbf{Evidence:} Tabela prawdy dwóch bramek dla jednego utrzymywanego pending, licznik ISR, końcowy clear, mret i kod wyjścia Hazard3.
|
||||
\par\textbf{Acceptance:} Hazard3: pending=1, blocked\_no\_msie=1, blocked\_no\_mie=1, delivered\_both=1, count=1, mcause=0x80000003, pending\_after=0, pass=1 i kod 0.
|
||||
\end{ESCBlockFrame}
|
||||
\begin{ESCBlockFrame}{TASK03 · Zapis dowodu ucznia}
|
||||
\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Macierz pending/MSIE/MIE}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Dostarczenie, clear i kod wyjścia}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill
|
||||
\end{ESCBlockFrame}
|
||||
\end{ESCTaskFrame}
|
||||
\ESCSectionBlockEnd
|
||||
|
||||
\end{document}
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,667 @@
|
||||
{
|
||||
"$schema": "../../../tools/card-layouts/schemas/card-source.schema.json",
|
||||
"schema": "esc-card-source.v1",
|
||||
"card": {
|
||||
"id": "mpabi-inf-c-10-traps-interrupt-control",
|
||||
"series": "c",
|
||||
"series_title": "C · Freestanding RV32I and K&R",
|
||||
"number": "10",
|
||||
"count": "13",
|
||||
"slug": "traps-interrupt-control",
|
||||
"title": "Pułapki i sterowanie przerwaniami RV32I",
|
||||
"topic": "ecall, mepc, mcause, machine software IRQ oraz bramki mie/mstatus",
|
||||
"project": "Freestanding C na RV32I",
|
||||
"subject": "Informatyka",
|
||||
"level": "Rok 1 · C10 · RV32I/Hazard3",
|
||||
"revision_date": "2026-07-20T00:00:00+02:00",
|
||||
"status": "Gotowa",
|
||||
"version": "v00.01",
|
||||
"uuid": "ec04ecee-1c4d-529a-a4e2-d3f9b40700ec",
|
||||
"author": "M. Pabiszczak",
|
||||
"year": "2026"
|
||||
},
|
||||
"generated": {
|
||||
"tex": "doc/generated/main.tex",
|
||||
"html": "web/index.html",
|
||||
"html_css": "web/style.css",
|
||||
"html_tree_inspector": false,
|
||||
"react_app": true
|
||||
},
|
||||
"render_dictionary": false,
|
||||
"template": "templates/karta-klasyczna.json",
|
||||
"title_block": {
|
||||
"category": "KARTA PRACY · INFORMATYKA",
|
||||
"prepared_by": "M. Pabiszczak",
|
||||
"prepared_on": "2026-07-20T00:00:00+02:00",
|
||||
"title": "Pułapki i sterowanie przerwaniami RV32I",
|
||||
"url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8fb9c110-557b-5081-8ae2-a56800f872e8",
|
||||
"repository_url": "https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-interrupts",
|
||||
"url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84",
|
||||
"url_domain": "mpabi.pl",
|
||||
"doc_uuid": "8fb9c110-557b-5081-8ae2-a56800f872e8",
|
||||
"revision": "v00.01",
|
||||
"issued_on": "2026-07-20T00:00:00+02:00",
|
||||
"series": "C-10",
|
||||
"document_type": "karta pracy",
|
||||
"tool": "card-layouts",
|
||||
"show_qr": true,
|
||||
"show_repository_qr": true,
|
||||
"height_cm": 2.6,
|
||||
"repeat_on_every_page": true,
|
||||
"replace_front_matter": true
|
||||
},
|
||||
"front_page_break": true,
|
||||
"front_page_scope": {
|
||||
"title": "Cel karty",
|
||||
"content_tex": "Uczeń odróżnia synchroniczny wyjątek od asynchronicznego przerwania, wyprowadza adres wznowienia z mepc oraz dowodzi, że samo pending nie wystarcza bez indywidualnej i globalnej bramki enable.",
|
||||
"scope_title": "Zakres i zachowane przykłady",
|
||||
"scope_content_tex": "Trzy obrazy RV32I działają na rzeczywistym modelu Hazard3. Task01 wykonuje \\texttt{ecall}; Task02 używa kontrolowanego machine software interrupt; Task03 mierzy macierz pending, \\texttt{mie.MSIE} i \\texttt{mstatus.MIE}. Peryferia pojawiają się dopiero w C12 i C13.\\par\\textbf{Układ każdego przykładu:} pełny profil A1--A8; widok N/D ma jawny powód, a diagram nie jest wymagany, gdy tekst daje lepszy dowód.",
|
||||
"scope_table": {
|
||||
"headers": [
|
||||
"Typ",
|
||||
"Task",
|
||||
"Idea",
|
||||
"Waga"
|
||||
],
|
||||
"rows": [
|
||||
{
|
||||
"chapter": "ECALL",
|
||||
"task": "Task01",
|
||||
"idea_tex": "synchroniczny cause 11, mepc i mret",
|
||||
"priority": "kluczowe",
|
||||
"key": true
|
||||
},
|
||||
{
|
||||
"chapter": "MSIP",
|
||||
"task": "Task02",
|
||||
"idea_tex": "MSIP, MSIE, MIE, vector 3 i mret",
|
||||
"priority": "kluczowe",
|
||||
"key": true
|
||||
},
|
||||
{
|
||||
"chapter": "GATE",
|
||||
"task": "Task03",
|
||||
"idea_tex": "to samo źródło, dwie niezależne bramki",
|
||||
"priority": "kluczowe",
|
||||
"key": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"side_margin_tree_layout": {
|
||||
"columns": [
|
||||
{
|
||||
"id": "zawodowe",
|
||||
"label": "TECH",
|
||||
"side": "left",
|
||||
"tree": "WE -> EK -> KW",
|
||||
"description": "Kod C, ABI i obserwacja RV32I."
|
||||
},
|
||||
{
|
||||
"id": "ogolne",
|
||||
"label": "OG",
|
||||
"side": "right",
|
||||
"tree": "WE -> EN -> KW",
|
||||
"description": "Przewidywanie, pomiar i wniosek."
|
||||
}
|
||||
]
|
||||
},
|
||||
"learning_effects": {
|
||||
"C10.EN01": {
|
||||
"bloom_level": "Analiza",
|
||||
"label": "Cause, gate i resume",
|
||||
"text": "Uczeń osobno zapisuje źródło zdarzenia, mcause, mepc, stan pending, obie bramki enable i efekt po mret.",
|
||||
"assessment_criteria": [
|
||||
"C10.KW01"
|
||||
]
|
||||
},
|
||||
"C10.EK01": {
|
||||
"bloom_level": "Zastosowanie",
|
||||
"label": "Pułapka widoczna w listingu",
|
||||
"text": "Uczeń uruchamia trzy obrazy Hazard3 i wiąże raporty runtime z instrukcjami ecall, CSR, wektorami i mret.",
|
||||
"assessment_criteria": [
|
||||
"C10.KW01"
|
||||
]
|
||||
}
|
||||
},
|
||||
"assessment_criteria": {
|
||||
"C10.KW01": {
|
||||
"text": "Task01: jeden ecall daje mcause=11, mepc jest zwiększone o 4 i kod normalny wznawia pracę. Task02: software IRQ ma mcause=0x80000003, pending 1 przed i w ISR, 0 po clear oraz jedno wznowienie. Task03: pending pozostaje zablokowane osobno bez MSIE i bez MIE, a jest dostarczone dokładnie raz dopiero z obiema bramkami.",
|
||||
"learning_effects": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
]
|
||||
}
|
||||
},
|
||||
"educational_requirements": {
|
||||
"C10.WE01": {
|
||||
"text": "Konfiguracja i analiza machine-mode trap z jawnym kontraktem źródła, pending, enable, handlera i adresu wznowienia.",
|
||||
"label": "ecall, mepc, mcause, machine software IRQ oraz bramki mie/mstatus",
|
||||
"learning_effects": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"learning_tree": {
|
||||
"schema": "we-learning-tree.v1",
|
||||
"policy": "Najpierw przewidywanie, następnie wykonanie i odczyt dowodu.",
|
||||
"ogolne": [
|
||||
{
|
||||
"effect_ref": "C10.EN01",
|
||||
"display": "EN C10 01",
|
||||
"source": "LOCAL",
|
||||
"official": "C",
|
||||
"local": "01",
|
||||
"kind": "EN",
|
||||
"tree_id": "C10.WE01.OG.LOCAL.C.01",
|
||||
"text": "Uczeń osobno zapisuje źródło zdarzenia, mcause, mepc, stan pending, obie bramki enable i efekt po mret.",
|
||||
"kw": [
|
||||
{
|
||||
"criterion_ref": "C10.KW01",
|
||||
"display": "KW C10 01",
|
||||
"source": "LOCAL",
|
||||
"kind": "KW",
|
||||
"official": "C",
|
||||
"local": "01",
|
||||
"text": "Kod, przewidywanie i pomiar tworzą jeden dowód."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"zawodowe": [
|
||||
{
|
||||
"effect_ref": "C10.EK01",
|
||||
"display": "EK C10 01",
|
||||
"source": "LOCAL",
|
||||
"official": "C",
|
||||
"local": "01",
|
||||
"kind": "EK",
|
||||
"tree_id": "C10.WE01.TECH.LOCAL.C.01",
|
||||
"text": "Uczeń uruchamia trzy obrazy Hazard3 i wiąże raporty runtime z instrukcjami ecall, CSR, wektorami i mret.",
|
||||
"kw": [
|
||||
{
|
||||
"criterion_ref": "C10.KW01",
|
||||
"display": "KW C10 01",
|
||||
"source": "LOCAL",
|
||||
"kind": "KW",
|
||||
"official": "C",
|
||||
"local": "01",
|
||||
"text": "Kod, przewidywanie i pomiar tworzą jeden dowód."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sections": [
|
||||
{
|
||||
"title": "1 — Wyjątek synchroniczny wskazuje instrukcję",
|
||||
"order": 10,
|
||||
"content_kind": "prose",
|
||||
"page_orientation": "portrait",
|
||||
"content_tex": "\\texttt{ecall} jest wykonywany przez bieżący strumień instrukcji, więc \\texttt{mcause=11} nie ma ustawionego bitu interrupt, a \\texttt{mepc} wskazuje samo \\texttt{ecall}. Handler Task01 świadomie zapisuje \\texttt{mepc+4}; bez tego \\texttt{mret} wykonałby ponownie tę samą instrukcję. Taka polityka jest poprawna dla tego kontrolowanego ECALL, ale nie wolno automatycznie pomijać instrukcji przy każdym błędzie.",
|
||||
"educational_requirement_refs": [
|
||||
"C10.WE01"
|
||||
],
|
||||
"learning_effect_refs": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"assessment_criterion_refs": [
|
||||
"C10.KW01"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "2 — Software IRQ jest asynchronicznym źródłem poziomowym",
|
||||
"order": 20,
|
||||
"content_kind": "prose",
|
||||
"page_orientation": "portrait",
|
||||
"content_tex": "Testbench ustawia MSIP hart0, a rdzeń widzi \\texttt{mip.MSIP}. Dostarczenie wymaga dodatkowo \\texttt{mie.MSIE=1} i \\texttt{mstatus.MIE=1}. Wektor 3 prowadzi do \\texttt{isr\\_machine\\_softirq}; handler odczytuje \\texttt{mcause=0x80000003}, usuwa źródło i dopiero potem publikuje licznik. \\texttt{mret} wraca do przerwanego kodu, a nie do instrukcji wybranej ręcznie przez aplikację.",
|
||||
"educational_requirement_refs": [
|
||||
"C10.WE01"
|
||||
],
|
||||
"learning_effect_refs": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"assessment_criterion_refs": [
|
||||
"C10.KW01"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "3 — Pending i enable odpowiadają na inne pytania",
|
||||
"order": 30,
|
||||
"content_kind": "prose",
|
||||
"page_orientation": "portrait",
|
||||
"content_tex": "Pending mówi, że źródło żąda obsługi. \\texttt{mie.MSIE} dopuszcza konkretną klasę, a \\texttt{mstatus.MIE} otwiera globalną bramkę machine mode. Task03 utrzymuje to samo pending i kolejno sprawdza dwa stany z jedną zamkniętą bramką oraz stan z obiema otwartymi. Dzięki temu kod 0 dowodzi całej macierzy, a nie tylko tego, że ISR kiedyś się wykonał.",
|
||||
"educational_requirement_refs": [
|
||||
"C10.WE01"
|
||||
],
|
||||
"learning_effect_refs": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"assessment_criterion_refs": [
|
||||
"C10.KW01"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Zadania — zachowane przykłady w profilu A1–A8",
|
||||
"order": 40,
|
||||
"content_kind": "tasks",
|
||||
"page_orientation": "portrait",
|
||||
"task_refs": [
|
||||
"task01",
|
||||
"task02",
|
||||
"task03"
|
||||
],
|
||||
"educational_requirement_refs": [
|
||||
"C10.WE01"
|
||||
],
|
||||
"learning_effect_refs": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"assessment_criterion_refs": [
|
||||
"C10.KW01"
|
||||
]
|
||||
}
|
||||
],
|
||||
"tasks": {
|
||||
"task01": {
|
||||
"title": "ECALL i wznowienie pod mepc+4",
|
||||
"uuid": "2cd1da12-b916-5def-b868-da4b13ff9089",
|
||||
"prompt_tex": "Przed uruchomieniem przewidź bit interrupt i kod mcause, wskaż wartość mepc oraz adres wznowienia. Wyjaśnij, co stałoby się bez zapisu mepc+4.",
|
||||
"criterion": "Hazard3: count=1, mcause=0x0000000b, resume_pc-mepc=4, resumed=1, pass=1 i kod 0.",
|
||||
"conclusion_tex": "",
|
||||
"render_task_acceptance": false,
|
||||
"viewpoints": [
|
||||
{
|
||||
"id": "A1",
|
||||
"status": "enabled",
|
||||
"title": "CONTEXT — kontrolowany wyjątek M-mode",
|
||||
"content_tex": "Granica zaczyna się na instrukcji \\texttt{ecall} w main i kończy po powrocie do kolejnej instrukcji. Nie ma zewnętrznego peryferium ani pending IRQ; rdzeń sam tworzy synchroniczną pułapkę."
|
||||
},
|
||||
{
|
||||
"id": "A2",
|
||||
"status": "enabled",
|
||||
"title": "STRUCTURE — mcause, mepc i mtvec",
|
||||
"content_tex": "\\texttt{mcause} zapisuje klasę 11 bez bitu interrupt, \\texttt{mepc} zapisuje adres ECALL, a baza \\texttt{mtvec} prowadzi wszystkie synchroniczne wyjątki do \\texttt{handle\\_exception}. Handler publikuje oryginał i osobny adres wznowienia."
|
||||
},
|
||||
{
|
||||
"id": "A3",
|
||||
"status": "enabled",
|
||||
"title": "DISPATCH — synchroniczny slot mtvec",
|
||||
"content_tex": "Sprzęt wybiera bazowy slot wektora, ponieważ zdarzenie jest wyjątkiem, nie IRQ. \\texttt{handle\\_exception} odczytuje mcause i obsługuje jedyny dopuszczony przypadek ECALL. To granica trap dispatch, choć nie ma tablicy callbacków."
|
||||
},
|
||||
{
|
||||
"id": "A4",
|
||||
"status": "enabled",
|
||||
"title": "APPLICATION — cause 11 i stały krok 4",
|
||||
"content_tex": "ECALL w RV32I jest instrukcją 32-bitową, dlatego dla tego przykładu poprawny resume ma wartość \\texttt{mepc+4}. Gate wymaga jednego wejścia, cause 11, delty 4 i ustawienia resumed dopiero po mret."
|
||||
},
|
||||
{
|
||||
"id": "A5",
|
||||
"status": "enabled",
|
||||
"title": "FLOW — ecall, save, patch, mret",
|
||||
"content_tex": "Normalny kod wykonuje ECALL. Rdzeń zapisuje mepc/mcause, skacze do wektora, handler odczytuje oba CSR i zapisuje nowe mepc. Epilog \\texttt{interrupt(\"machine\")} kończy się mret; dopiero potem main zapisuje resumed."
|
||||
},
|
||||
{
|
||||
"id": "A6",
|
||||
"status": "enabled",
|
||||
"title": "STATE — RUNNING, TRAP, RESUMED",
|
||||
"content_tex": "Stan przechodzi \\texttt{RUNNING -> TRAP(mepc=ecall,cause=11) -> RESUMED(pc=mepc+4)}. Licznik 1 odróżnia pojedyncze wznowienie od pętli ponownego wykonywania ECALL."
|
||||
},
|
||||
{
|
||||
"id": "A7",
|
||||
"status": "enabled",
|
||||
"title": "RUNTIME — ecall i mret w ELF",
|
||||
"content_tex": "Oracle porównuje raportowane adresy i niezależnie wymaga różnicy 4. Objdump musi pokazać \\texttt{ecall} w main oraz \\texttt{mret} w handlerze. Segmenty LOAD pozostają rozdzielone R-X/R-W."
|
||||
},
|
||||
{
|
||||
"id": "A8",
|
||||
"status": "enabled",
|
||||
"title": "PATTERNS — explicit resume policy",
|
||||
"content_tex": "Wzorzec handlera wyjątku obejmuje jawną decyzję: retry, skip albo terminate. Task01 wybiera skip tylko dla znanego ECALL. Dla faultu pamięci bezwarunkowe mepc+4 mogłoby ukryć błąd i jest niedozwolone."
|
||||
}
|
||||
],
|
||||
"flow": [
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a1",
|
||||
"title": "A1 CONTEXT · AKTYWNE — kontrolowany wyjątek M-mode",
|
||||
"content_tex": "\\textbf{Zachowany przykład:} \\nolinkurl{src/tasks/task01_ecall_resume.c}.\\par Granica zaczyna się na instrukcji \\texttt{ecall} w main i kończy po powrocie do kolejnej instrukcji. Nie ma zewnętrznego peryferium ani pending IRQ; rdzeń sam tworzy synchroniczną pułapkę."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a2",
|
||||
"title": "A2 STRUCTURE · AKTYWNE — mcause, mepc i mtvec",
|
||||
"content_tex": "\\texttt{mcause} zapisuje klasę 11 bez bitu interrupt, \\texttt{mepc} zapisuje adres ECALL, a baza \\texttt{mtvec} prowadzi wszystkie synchroniczne wyjątki do \\texttt{handle\\_exception}. Handler publikuje oryginał i osobny adres wznowienia."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a3",
|
||||
"title": "A3 DISPATCH · AKTYWNE — synchroniczny slot mtvec",
|
||||
"content_tex": "Sprzęt wybiera bazowy slot wektora, ponieważ zdarzenie jest wyjątkiem, nie IRQ. \\texttt{handle\\_exception} odczytuje mcause i obsługuje jedyny dopuszczony przypadek ECALL. To granica trap dispatch, choć nie ma tablicy callbacków."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a4",
|
||||
"title": "A4 APPLICATION · AKTYWNE — cause 11 i stały krok 4",
|
||||
"content_tex": "ECALL w RV32I jest instrukcją 32-bitową, dlatego dla tego przykładu poprawny resume ma wartość \\texttt{mepc+4}. Gate wymaga jednego wejścia, cause 11, delty 4 i ustawienia resumed dopiero po mret."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a5",
|
||||
"title": "A5 FLOW · AKTYWNE — ecall, save, patch, mret",
|
||||
"content_tex": "Normalny kod wykonuje ECALL. Rdzeń zapisuje mepc/mcause, skacze do wektora, handler odczytuje oba CSR i zapisuje nowe mepc. Epilog \\texttt{interrupt(\"machine\")} kończy się mret; dopiero potem main zapisuje resumed."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a6",
|
||||
"title": "A6 STATE · AKTYWNE — RUNNING, TRAP, RESUMED",
|
||||
"content_tex": "Stan przechodzi \\texttt{RUNNING -> TRAP(mepc=ecall,cause=11) -> RESUMED(pc=mepc+4)}. Licznik 1 odróżnia pojedyncze wznowienie od pętli ponownego wykonywania ECALL."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a7",
|
||||
"title": "A7 RUNTIME · AKTYWNE — ecall i mret w ELF",
|
||||
"content_tex": "Oracle porównuje raportowane adresy i niezależnie wymaga różnicy 4. Objdump musi pokazać \\texttt{ecall} w main oraz \\texttt{mret} w handlerze. Segmenty LOAD pozostają rozdzielone R-X/R-W."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.a8",
|
||||
"title": "A8 PATTERNS · AKTYWNE — explicit resume policy",
|
||||
"content_tex": "Wzorzec handlera wyjątku obejmuje jawną decyzję: retry, skip albo terminate. Task01 wybiera skip tylko dla znanego ECALL. Dla faultu pamięci bezwarunkowe mepc+4 mogłoby ukryć błąd i jest niedozwolone."
|
||||
},
|
||||
{
|
||||
"kind": "exercise",
|
||||
"id": "task01.proof",
|
||||
"title": "Przewidywanie → wykonanie → wniosek",
|
||||
"prompt_tex": "Przed uruchomieniem przewidź bit interrupt i kod mcause, wskaż wartość mepc oraz adres wznowienia. Wyjaśnij, co stałoby się bez zapisu mepc+4.",
|
||||
"evidence_tex": "Adres ecall i dwa adresy mepc z raportu/listingu, cause 11, instrukcja mret oraz kod wyjścia Hazard3.",
|
||||
"criterion": "Hazard3: count=1, mcause=0x0000000b, resume_pc-mepc=4, resumed=1, pass=1 i kod 0."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task01.worksheet",
|
||||
"title": "TASK01 · Zapis dowodu ucznia",
|
||||
"content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. mcause, mepc i adres wznowienia}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. ecall/mret w listingu i kod wyjścia}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill"
|
||||
}
|
||||
],
|
||||
"educational_requirement_refs": [
|
||||
"C10.WE01"
|
||||
],
|
||||
"learning_effect_refs": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"assessment_criterion_ref": "C10.KW01"
|
||||
},
|
||||
"task02": {
|
||||
"title": "Machine software IRQ i clear źródła",
|
||||
"uuid": "a4b503ba-cacc-5af1-9ecd-31f51563ca76",
|
||||
"prompt_tex": "Zapisz stan pending przed globalnym enable, mcause w ISR i pending po clear. Rozdziel źródło MSIP od obu bramek oraz wskaż, dlaczego handler musi usunąć źródło przed mret.",
|
||||
"criterion": "Hazard3: count=1, mcause=0x80000003, pending_before=1, pending_in_handler=1, pending_after=0, resumed=1, pass=1 i kod 0.",
|
||||
"conclusion_tex": "",
|
||||
"render_task_acceptance": false,
|
||||
"viewpoints": [
|
||||
{
|
||||
"id": "A1",
|
||||
"status": "enabled",
|
||||
"title": "CONTEXT — kontrolowane źródło bez peryferium",
|
||||
"content_tex": "\\texttt{tb\\_set\\_softirq(0)} podnosi machine software interrupt hart0. Testbench jest źródłem, CSR są kontrolą rdzenia, ISR usuwa żądanie, a main ocenia wznowienie. UART/GPIO nie uczestniczą."
|
||||
},
|
||||
{
|
||||
"id": "A2",
|
||||
"status": "enabled",
|
||||
"title": "STRUCTURE — trzy bity i jeden wektor",
|
||||
"content_tex": "Źródło jest widoczne jako \\texttt{mip.MSIP}; indywidualna bramka to \\texttt{mie.MSIE}, globalna to \\texttt{mstatus.MIE}. Cause 3 w trybie vectored wybiera slot 3 i symbol \\texttt{isr\\_machine\\_softirq}."
|
||||
},
|
||||
{
|
||||
"id": "A3",
|
||||
"status": "enabled",
|
||||
"title": "DISPATCH — sprzęt wybiera vector 3",
|
||||
"content_tex": "Bit interrupt w mcause i kod 3 powodują sprzętowy wybór slotu machine software IRQ. Nie jest to statyczne jal z main. Po wejściu symbol handlera jest już określony przez wektor, a mret odtwarza przerwany kontekst."
|
||||
},
|
||||
{
|
||||
"id": "A4",
|
||||
"status": "enabled",
|
||||
"title": "APPLICATION — pending 1 do 0",
|
||||
"content_tex": "Przy MSIE=1 i MIE=0 źródło jest już pending, lecz licznik wynosi 0. Po otwarciu MIE handler widzi \\texttt{0x80000003} i pending=1, wykonuje clear, zwiększa licznik, a po mret main mierzy pending=0."
|
||||
},
|
||||
{
|
||||
"id": "A5",
|
||||
"status": "enabled",
|
||||
"title": "FLOW — configure, assert, observe, enable",
|
||||
"content_tex": "Kolejność eliminuje wyścig pomiaru: najpierw wyłącz wszystko, ustaw MSIE, podnieś źródło, zmierz pending, dopiero potem ustaw MIE. Handler odczytuje cause/pending przed clear i publikuje licznik po clear."
|
||||
},
|
||||
{
|
||||
"id": "A6",
|
||||
"status": "enabled",
|
||||
"title": "STATE — MASKED_PENDING, ACTIVE, CLEARED",
|
||||
"content_tex": "Źródło przechodzi do \\texttt{MASKED\\_PENDING}, bo globalna bramka jest zamknięta. Po MIE staje się ACTIVE; clear w ISR tworzy CLEARED. Resumed=1 jest osobnym stanem normalnego kodu po mret."
|
||||
},
|
||||
{
|
||||
"id": "A7",
|
||||
"status": "enabled",
|
||||
"title": "RUNTIME — cause z bitem 31",
|
||||
"content_tex": "Wartość \\texttt{0x80000003} łączy bit interrupt i kod 3. Listing ma pokazać CSR dla mie/mstatus/mip, dostęp do testbench clear oraz mret. Oracle wymaga całego śladu, nie tylko pass."
|
||||
},
|
||||
{
|
||||
"id": "A8",
|
||||
"status": "enabled",
|
||||
"title": "PATTERNS — clear level source before publish",
|
||||
"content_tex": "Źródło poziomowe usuwa się przed opublikowaniem ukończenia ISR. Gdyby licznik wzrósł bez clear, po mret żądanie pozostałoby aktywne i handler mógłby wejść ponownie."
|
||||
}
|
||||
],
|
||||
"flow": [
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a1",
|
||||
"title": "A1 CONTEXT · AKTYWNE — kontrolowane źródło bez peryferium",
|
||||
"content_tex": "\\textbf{Zachowany przykład:} \\nolinkurl{src/tasks/task02_machine_software_irq.c}.\\par \\texttt{tb\\_set\\_softirq(0)} podnosi machine software interrupt hart0. Testbench jest źródłem, CSR są kontrolą rdzenia, ISR usuwa żądanie, a main ocenia wznowienie. UART/GPIO nie uczestniczą."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a2",
|
||||
"title": "A2 STRUCTURE · AKTYWNE — trzy bity i jeden wektor",
|
||||
"content_tex": "Źródło jest widoczne jako \\texttt{mip.MSIP}; indywidualna bramka to \\texttt{mie.MSIE}, globalna to \\texttt{mstatus.MIE}. Cause 3 w trybie vectored wybiera slot 3 i symbol \\texttt{isr\\_machine\\_softirq}."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a3",
|
||||
"title": "A3 DISPATCH · AKTYWNE — sprzęt wybiera vector 3",
|
||||
"content_tex": "Bit interrupt w mcause i kod 3 powodują sprzętowy wybór slotu machine software IRQ. Nie jest to statyczne jal z main. Po wejściu symbol handlera jest już określony przez wektor, a mret odtwarza przerwany kontekst."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a4",
|
||||
"title": "A4 APPLICATION · AKTYWNE — pending 1 do 0",
|
||||
"content_tex": "Przy MSIE=1 i MIE=0 źródło jest już pending, lecz licznik wynosi 0. Po otwarciu MIE handler widzi \\texttt{0x80000003} i pending=1, wykonuje clear, zwiększa licznik, a po mret main mierzy pending=0."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a5",
|
||||
"title": "A5 FLOW · AKTYWNE — configure, assert, observe, enable",
|
||||
"content_tex": "Kolejność eliminuje wyścig pomiaru: najpierw wyłącz wszystko, ustaw MSIE, podnieś źródło, zmierz pending, dopiero potem ustaw MIE. Handler odczytuje cause/pending przed clear i publikuje licznik po clear."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a6",
|
||||
"title": "A6 STATE · AKTYWNE — MASKED_PENDING, ACTIVE, CLEARED",
|
||||
"content_tex": "Źródło przechodzi do \\texttt{MASKED\\_PENDING}, bo globalna bramka jest zamknięta. Po MIE staje się ACTIVE; clear w ISR tworzy CLEARED. Resumed=1 jest osobnym stanem normalnego kodu po mret."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a7",
|
||||
"title": "A7 RUNTIME · AKTYWNE — cause z bitem 31",
|
||||
"content_tex": "Wartość \\texttt{0x80000003} łączy bit interrupt i kod 3. Listing ma pokazać CSR dla mie/mstatus/mip, dostęp do testbench clear oraz mret. Oracle wymaga całego śladu, nie tylko pass."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.a8",
|
||||
"title": "A8 PATTERNS · AKTYWNE — clear level source before publish",
|
||||
"content_tex": "Źródło poziomowe usuwa się przed opublikowaniem ukończenia ISR. Gdyby licznik wzrósł bez clear, po mret żądanie pozostałoby aktywne i handler mógłby wejść ponownie."
|
||||
},
|
||||
{
|
||||
"kind": "exercise",
|
||||
"id": "task02.proof",
|
||||
"title": "Przewidywanie → wykonanie → wniosek",
|
||||
"prompt_tex": "Zapisz stan pending przed globalnym enable, mcause w ISR i pending po clear. Rozdziel źródło MSIP od obu bramek oraz wskaż, dlaczego handler musi usunąć źródło przed mret.",
|
||||
"evidence_tex": "Ślad źródło→pending→MSIE/MIE→vector 3→ISR→clear→mret, raport globali i kod wyjścia Hazard3.",
|
||||
"criterion": "Hazard3: count=1, mcause=0x80000003, pending_before=1, pending_in_handler=1, pending_after=0, resumed=1, pass=1 i kod 0."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task02.worksheet",
|
||||
"title": "TASK02 · Zapis dowodu ucznia",
|
||||
"content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. Pending i bramki przed wejściem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. mcause, clear, mret i wznowienie}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill"
|
||||
}
|
||||
],
|
||||
"educational_requirement_refs": [
|
||||
"C10.WE01"
|
||||
],
|
||||
"learning_effect_refs": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"assessment_criterion_ref": "C10.KW01"
|
||||
},
|
||||
"task03": {
|
||||
"title": "Macierz pending, MSIE i MIE",
|
||||
"uuid": "f56dba83-f7a9-5643-8f2e-84df1e8a2190",
|
||||
"prompt_tex": "Wypełnij trzy wiersze: pending=1 z samym MIE, pending=1 z samym MSIE oraz pending=1 z obiema bramkami. Przewidź licznik ISR i końcowy pending.",
|
||||
"criterion": "Hazard3: pending=1, blocked_no_msie=1, blocked_no_mie=1, delivered_both=1, count=1, mcause=0x80000003, pending_after=0, pass=1 i kod 0.",
|
||||
"conclusion_tex": "",
|
||||
"render_task_acceptance": false,
|
||||
"viewpoints": [
|
||||
{
|
||||
"id": "A1",
|
||||
"status": "enabled",
|
||||
"title": "CONTEXT — jedna zmienna, dwie kontrolki",
|
||||
"content_tex": "Bodziec MSIP pozostaje ten sam podczas dwóch prób blokowanych i próby dostarczonej. Przykład zmienia wyłącznie bramki rdzenia, więc nie myli nowego zdarzenia z nową konfiguracją."
|
||||
},
|
||||
{
|
||||
"id": "A2",
|
||||
"status": "enabled",
|
||||
"title": "STRUCTURE — macierz 1×2×2",
|
||||
"content_tex": "Oś danych to pending=1. Dwie osie sterujące to MSIE i MIE. Cztery kombinacje mają jeden stan dostarczalny: oba bity 1. Przykład mierzy trzy istotne wiersze przy utrzymanym pending."
|
||||
},
|
||||
{
|
||||
"id": "A3",
|
||||
"status": "enabled",
|
||||
"title": "DISPATCH — wejście dopiero dla 1/1",
|
||||
"content_tex": "Sprzętowy dispatch do vector 3 nie zachodzi przy żadnej pojedynczej otwartej bramce. Dopiero MSIE=1 i MIE=1 pozwalają utworzyć trap, zapisać cause i wejść do ISR kończącego się mret."
|
||||
},
|
||||
{
|
||||
"id": "A4",
|
||||
"status": "enabled",
|
||||
"title": "APPLICATION — dwa razy blocked, raz delivered",
|
||||
"content_tex": "Przy MIE=1/MSIE=0 licznik zostaje 0. Przy MIE=0/MSIE=1 również zostaje 0. Przy obu równych 1 rośnie dokładnie do 1, mcause ma wartość 0x80000003, a clear zeruje pending."
|
||||
},
|
||||
{
|
||||
"id": "A5",
|
||||
"status": "enabled",
|
||||
"title": "FLOW — nie zmieniaj źródła między próbami",
|
||||
"content_tex": "Program podnosi MSIP raz, następnie testuje global-only, individual-only i both. Globalny bit jest zamykany przed zmianą MSIE, aby dostarczenie nie zaszło między pomiarem a zapisaniem wyniku."
|
||||
},
|
||||
{
|
||||
"id": "A6",
|
||||
"status": "enabled",
|
||||
"title": "STATE — P10, P01, P11, CLEAR",
|
||||
"content_tex": "Skrót \\texttt{Pxy} oznacza pending=1, MSIE=x, MIE=y. Ślad to \\texttt{P01(blocked) -> P10(blocked) -> P11(active) -> CLEAR}. Licznik zmienia się tylko na trzeciej krawędzi."
|
||||
},
|
||||
{
|
||||
"id": "A7",
|
||||
"status": "enabled",
|
||||
"title": "RUNTIME — odczyt mip, zapisy mie/mstatus",
|
||||
"content_tex": "Raport utrwala trzy decyzje i cause. Listing rozdziela \\texttt{csrs/csrc mie}, \\texttt{csrs/csrc mstatus} oraz odczyt mip. Objdump niezależnie potwierdza mret w ISR."
|
||||
},
|
||||
{
|
||||
"id": "A8",
|
||||
"status": "enabled",
|
||||
"title": "PATTERNS — source, individual, global gate",
|
||||
"content_tex": "Trzywarstwowy model zapobiega typowemu błędowi: pending nie znaczy delivered. Ten sam wzorzec wróci dla MTIP/MTIE oraz external IRQ z enable peryferium, kontrolera i globalnym MIE."
|
||||
}
|
||||
],
|
||||
"flow": [
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a1",
|
||||
"title": "A1 CONTEXT · AKTYWNE — jedna zmienna, dwie kontrolki",
|
||||
"content_tex": "\\textbf{Zachowany przykład:} \\nolinkurl{src/tasks/task03_pending_enable_matrix.c}.\\par Bodziec MSIP pozostaje ten sam podczas dwóch prób blokowanych i próby dostarczonej. Przykład zmienia wyłącznie bramki rdzenia, więc nie myli nowego zdarzenia z nową konfiguracją."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a2",
|
||||
"title": "A2 STRUCTURE · AKTYWNE — macierz 1×2×2",
|
||||
"content_tex": "Oś danych to pending=1. Dwie osie sterujące to MSIE i MIE. Cztery kombinacje mają jeden stan dostarczalny: oba bity 1. Przykład mierzy trzy istotne wiersze przy utrzymanym pending."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a3",
|
||||
"title": "A3 DISPATCH · AKTYWNE — wejście dopiero dla 1/1",
|
||||
"content_tex": "Sprzętowy dispatch do vector 3 nie zachodzi przy żadnej pojedynczej otwartej bramce. Dopiero MSIE=1 i MIE=1 pozwalają utworzyć trap, zapisać cause i wejść do ISR kończącego się mret."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a4",
|
||||
"title": "A4 APPLICATION · AKTYWNE — dwa razy blocked, raz delivered",
|
||||
"content_tex": "Przy MIE=1/MSIE=0 licznik zostaje 0. Przy MIE=0/MSIE=1 również zostaje 0. Przy obu równych 1 rośnie dokładnie do 1, mcause ma wartość 0x80000003, a clear zeruje pending."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a5",
|
||||
"title": "A5 FLOW · AKTYWNE — nie zmieniaj źródła między próbami",
|
||||
"content_tex": "Program podnosi MSIP raz, następnie testuje global-only, individual-only i both. Globalny bit jest zamykany przed zmianą MSIE, aby dostarczenie nie zaszło między pomiarem a zapisaniem wyniku."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a6",
|
||||
"title": "A6 STATE · AKTYWNE — P10, P01, P11, CLEAR",
|
||||
"content_tex": "Skrót \\texttt{Pxy} oznacza pending=1, MSIE=x, MIE=y. Ślad to \\texttt{P01(blocked) -> P10(blocked) -> P11(active) -> CLEAR}. Licznik zmienia się tylko na trzeciej krawędzi."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a7",
|
||||
"title": "A7 RUNTIME · AKTYWNE — odczyt mip, zapisy mie/mstatus",
|
||||
"content_tex": "Raport utrwala trzy decyzje i cause. Listing rozdziela \\texttt{csrs/csrc mie}, \\texttt{csrs/csrc mstatus} oraz odczyt mip. Objdump niezależnie potwierdza mret w ISR."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.a8",
|
||||
"title": "A8 PATTERNS · AKTYWNE — source, individual, global gate",
|
||||
"content_tex": "Trzywarstwowy model zapobiega typowemu błędowi: pending nie znaczy delivered. Ten sam wzorzec wróci dla MTIP/MTIE oraz external IRQ z enable peryferium, kontrolera i globalnym MIE."
|
||||
},
|
||||
{
|
||||
"kind": "exercise",
|
||||
"id": "task03.proof",
|
||||
"title": "Przewidywanie → wykonanie → wniosek",
|
||||
"prompt_tex": "Wypełnij trzy wiersze: pending=1 z samym MIE, pending=1 z samym MSIE oraz pending=1 z obiema bramkami. Przewidź licznik ISR i końcowy pending.",
|
||||
"evidence_tex": "Tabela prawdy dwóch bramek dla jednego utrzymywanego pending, licznik ISR, końcowy clear, mret i kod wyjścia Hazard3.",
|
||||
"criterion": "Hazard3: pending=1, blocked_no_msie=1, blocked_no_mie=1, delivered_both=1, count=1, mcause=0x80000003, pending_after=0, pass=1 i kod 0."
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"id": "task03.worksheet",
|
||||
"title": "TASK03 · Zapis dowodu ucznia",
|
||||
"content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. Macierz pending/MSIE/MIE}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Dostarczenie, clear i kod wyjścia}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill"
|
||||
}
|
||||
],
|
||||
"educational_requirement_refs": [
|
||||
"C10.WE01"
|
||||
],
|
||||
"learning_effect_refs": [
|
||||
"C10.EN01",
|
||||
"C10.EK01"
|
||||
],
|
||||
"assessment_criterion_ref": "C10.KW01"
|
||||
}
|
||||
},
|
||||
"tasks_order": [
|
||||
"task01",
|
||||
"task02",
|
||||
"task03"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"card": {
|
||||
"number": "10",
|
||||
"slug": "traps-interrupt-control",
|
||||
"title": "Pułapki i sterowanie przerwaniami RV32I",
|
||||
"topic": "ecall, mepc, mcause, machine software IRQ oraz bramki mie/mstatus",
|
||||
"status": "Gotowa",
|
||||
"version": "v00.01",
|
||||
"revision_date": "2026-07-20T00:00:00+02:00"
|
||||
},
|
||||
"scope_headers": ["Typ", "Task", "Idea", "Waga"],
|
||||
"front": {
|
||||
"goal": "Uczeń odróżnia synchroniczny wyjątek od asynchronicznego przerwania, wyprowadza adres wznowienia z mepc oraz dowodzi, że samo pending nie wystarcza bez indywidualnej i globalnej bramki enable.",
|
||||
"scope": "Trzy obrazy RV32I działają na rzeczywistym modelu Hazard3. Task01 wykonuje \\texttt{ecall}; Task02 używa kontrolowanego machine software interrupt; Task03 mierzy macierz pending, \\texttt{mie.MSIE} i \\texttt{mstatus.MIE}. Peryferia pojawiają się dopiero w C12 i C13."
|
||||
},
|
||||
"learning": {
|
||||
"reasoning_label": "Cause, gate i resume",
|
||||
"reasoning": "Uczeń osobno zapisuje źródło zdarzenia, mcause, mepc, stan pending, obie bramki enable i efekt po mret.",
|
||||
"practice_label": "Pułapka widoczna w listingu",
|
||||
"practice": "Uczeń uruchamia trzy obrazy Hazard3 i wiąże raporty runtime z instrukcjami ecall, CSR, wektorami i mret.",
|
||||
"criterion": "Task01: jeden ecall daje mcause=11, mepc jest zwiększone o 4 i kod normalny wznawia pracę. Task02: software IRQ ma mcause=0x80000003, pending 1 przed i w ISR, 0 po clear oraz jedno wznowienie. Task03: pending pozostaje zablokowane osobno bez MSIE i bez MIE, a jest dostarczone dokładnie raz dopiero z obiema bramkami.",
|
||||
"requirement": "Konfiguracja i analiza machine-mode trap z jawnym kontraktem źródła, pending, enable, handlera i adresu wznowienia."
|
||||
},
|
||||
"sections": [
|
||||
{
|
||||
"title": "1 — Wyjątek synchroniczny wskazuje instrukcję",
|
||||
"content_tex": "\\texttt{ecall} jest wykonywany przez bieżący strumień instrukcji, więc \\texttt{mcause=11} nie ma ustawionego bitu interrupt, a \\texttt{mepc} wskazuje samo \\texttt{ecall}. Handler Task01 świadomie zapisuje \\texttt{mepc+4}; bez tego \\texttt{mret} wykonałby ponownie tę samą instrukcję. Taka polityka jest poprawna dla tego kontrolowanego ECALL, ale nie wolno automatycznie pomijać instrukcji przy każdym błędzie."
|
||||
},
|
||||
{
|
||||
"title": "2 — Software IRQ jest asynchronicznym źródłem poziomowym",
|
||||
"content_tex": "Testbench ustawia MSIP hart0, a rdzeń widzi \\texttt{mip.MSIP}. Dostarczenie wymaga dodatkowo \\texttt{mie.MSIE=1} i \\texttt{mstatus.MIE=1}. Wektor 3 prowadzi do \\texttt{isr\\_machine\\_softirq}; handler odczytuje \\texttt{mcause=0x80000003}, usuwa źródło i dopiero potem publikuje licznik. \\texttt{mret} wraca do przerwanego kodu, a nie do instrukcji wybranej ręcznie przez aplikację."
|
||||
},
|
||||
{
|
||||
"title": "3 — Pending i enable odpowiadają na inne pytania",
|
||||
"content_tex": "Pending mówi, że źródło żąda obsługi. \\texttt{mie.MSIE} dopuszcza konkretną klasę, a \\texttt{mstatus.MIE} otwiera globalną bramkę machine mode. Task03 utrzymuje to samo pending i kolejno sprawdza dwa stany z jedną zamkniętą bramką oraz stan z obiema otwartymi. Dzięki temu kod 0 dowodzi całej macierzy, a nie tylko tego, że ISR kiedyś się wykonał."
|
||||
}
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"id": "task01",
|
||||
"chapter": "ECALL",
|
||||
"title": "ECALL i wznowienie pod mepc+4",
|
||||
"idea_tex": "synchroniczny cause 11, mepc i mret",
|
||||
"priority": "kluczowe",
|
||||
"key": true,
|
||||
"prompt_tex": "Przed uruchomieniem przewidź bit interrupt i kod mcause, wskaż wartość mepc oraz adres wznowienia. Wyjaśnij, co stałoby się bez zapisu mepc+4.",
|
||||
"criterion": "Hazard3: count=1, mcause=0x0000000b, resume_pc-mepc=4, resumed=1, pass=1 i kod 0.",
|
||||
"evidence_tex": "Adres ecall i dwa adresy mepc z raportu/listingu, cause 11, instrukcja mret oraz kod wyjścia Hazard3.",
|
||||
"worksheet_step2": "mcause, mepc i adres wznowienia",
|
||||
"worksheet_step3": "ecall/mret w listingu i kod wyjścia",
|
||||
"viewpoints": [
|
||||
{"id":"A1","status":"enabled","title":"CONTEXT — kontrolowany wyjątek M-mode","content_tex":"Granica zaczyna się na instrukcji \\texttt{ecall} w main i kończy po powrocie do kolejnej instrukcji. Nie ma zewnętrznego peryferium ani pending IRQ; rdzeń sam tworzy synchroniczną pułapkę."},
|
||||
{"id":"A2","status":"enabled","title":"STRUCTURE — mcause, mepc i mtvec","content_tex":"\\texttt{mcause} zapisuje klasę 11 bez bitu interrupt, \\texttt{mepc} zapisuje adres ECALL, a baza \\texttt{mtvec} prowadzi wszystkie synchroniczne wyjątki do \\texttt{handle\\_exception}. Handler publikuje oryginał i osobny adres wznowienia."},
|
||||
{"id":"A3","status":"enabled","title":"DISPATCH — synchroniczny slot mtvec","content_tex":"Sprzęt wybiera bazowy slot wektora, ponieważ zdarzenie jest wyjątkiem, nie IRQ. \\texttt{handle\\_exception} odczytuje mcause i obsługuje jedyny dopuszczony przypadek ECALL. To granica trap dispatch, choć nie ma tablicy callbacków."},
|
||||
{"id":"A4","status":"enabled","title":"APPLICATION — cause 11 i stały krok 4","content_tex":"ECALL w RV32I jest instrukcją 32-bitową, dlatego dla tego przykładu poprawny resume ma wartość \\texttt{mepc+4}. Gate wymaga jednego wejścia, cause 11, delty 4 i ustawienia resumed dopiero po mret."},
|
||||
{"id":"A5","status":"enabled","title":"FLOW — ecall, save, patch, mret","content_tex":"Normalny kod wykonuje ECALL. Rdzeń zapisuje mepc/mcause, skacze do wektora, handler odczytuje oba CSR i zapisuje nowe mepc. Epilog \\texttt{interrupt(\"machine\")} kończy się mret; dopiero potem main zapisuje resumed."},
|
||||
{"id":"A6","status":"enabled","title":"STATE — RUNNING, TRAP, RESUMED","content_tex":"Stan przechodzi \\texttt{RUNNING -> TRAP(mepc=ecall,cause=11) -> RESUMED(pc=mepc+4)}. Licznik 1 odróżnia pojedyncze wznowienie od pętli ponownego wykonywania ECALL."},
|
||||
{"id":"A7","status":"enabled","title":"RUNTIME — ecall i mret w ELF","content_tex":"Oracle porównuje raportowane adresy i niezależnie wymaga różnicy 4. Objdump musi pokazać \\texttt{ecall} w main oraz \\texttt{mret} w handlerze. Segmenty LOAD pozostają rozdzielone R-X/R-W."},
|
||||
{"id":"A8","status":"enabled","title":"PATTERNS — explicit resume policy","content_tex":"Wzorzec handlera wyjątku obejmuje jawną decyzję: retry, skip albo terminate. Task01 wybiera skip tylko dla znanego ECALL. Dla faultu pamięci bezwarunkowe mepc+4 mogłoby ukryć błąd i jest niedozwolone."}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task02",
|
||||
"chapter": "MSIP",
|
||||
"title": "Machine software IRQ i clear źródła",
|
||||
"idea_tex": "MSIP, MSIE, MIE, vector 3 i mret",
|
||||
"priority": "kluczowe",
|
||||
"key": true,
|
||||
"prompt_tex": "Zapisz stan pending przed globalnym enable, mcause w ISR i pending po clear. Rozdziel źródło MSIP od obu bramek oraz wskaż, dlaczego handler musi usunąć źródło przed mret.",
|
||||
"criterion": "Hazard3: count=1, mcause=0x80000003, pending_before=1, pending_in_handler=1, pending_after=0, resumed=1, pass=1 i kod 0.",
|
||||
"evidence_tex": "Ślad źródło→pending→MSIE/MIE→vector 3→ISR→clear→mret, raport globali i kod wyjścia Hazard3.",
|
||||
"worksheet_step2": "Pending i bramki przed wejściem",
|
||||
"worksheet_step3": "mcause, clear, mret i wznowienie",
|
||||
"viewpoints": [
|
||||
{"id":"A1","status":"enabled","title":"CONTEXT — kontrolowane źródło bez peryferium","content_tex":"\\texttt{tb\\_set\\_softirq(0)} podnosi machine software interrupt hart0. Testbench jest źródłem, CSR są kontrolą rdzenia, ISR usuwa żądanie, a main ocenia wznowienie. UART/GPIO nie uczestniczą."},
|
||||
{"id":"A2","status":"enabled","title":"STRUCTURE — trzy bity i jeden wektor","content_tex":"Źródło jest widoczne jako \\texttt{mip.MSIP}; indywidualna bramka to \\texttt{mie.MSIE}, globalna to \\texttt{mstatus.MIE}. Cause 3 w trybie vectored wybiera slot 3 i symbol \\texttt{isr\\_machine\\_softirq}."},
|
||||
{"id":"A3","status":"enabled","title":"DISPATCH — sprzęt wybiera vector 3","content_tex":"Bit interrupt w mcause i kod 3 powodują sprzętowy wybór slotu machine software IRQ. Nie jest to statyczne jal z main. Po wejściu symbol handlera jest już określony przez wektor, a mret odtwarza przerwany kontekst."},
|
||||
{"id":"A4","status":"enabled","title":"APPLICATION — pending 1 do 0","content_tex":"Przy MSIE=1 i MIE=0 źródło jest już pending, lecz licznik wynosi 0. Po otwarciu MIE handler widzi \\texttt{0x80000003} i pending=1, wykonuje clear, zwiększa licznik, a po mret main mierzy pending=0."},
|
||||
{"id":"A5","status":"enabled","title":"FLOW — configure, assert, observe, enable","content_tex":"Kolejność eliminuje wyścig pomiaru: najpierw wyłącz wszystko, ustaw MSIE, podnieś źródło, zmierz pending, dopiero potem ustaw MIE. Handler odczytuje cause/pending przed clear i publikuje licznik po clear."},
|
||||
{"id":"A6","status":"enabled","title":"STATE — MASKED_PENDING, ACTIVE, CLEARED","content_tex":"Źródło przechodzi do \\texttt{MASKED\\_PENDING}, bo globalna bramka jest zamknięta. Po MIE staje się ACTIVE; clear w ISR tworzy CLEARED. Resumed=1 jest osobnym stanem normalnego kodu po mret."},
|
||||
{"id":"A7","status":"enabled","title":"RUNTIME — cause z bitem 31","content_tex":"Wartość \\texttt{0x80000003} łączy bit interrupt i kod 3. Listing ma pokazać CSR dla mie/mstatus/mip, dostęp do testbench clear oraz mret. Oracle wymaga całego śladu, nie tylko pass."},
|
||||
{"id":"A8","status":"enabled","title":"PATTERNS — clear level source before publish","content_tex":"Źródło poziomowe usuwa się przed opublikowaniem ukończenia ISR. Gdyby licznik wzrósł bez clear, po mret żądanie pozostałoby aktywne i handler mógłby wejść ponownie."}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "task03",
|
||||
"chapter": "GATE",
|
||||
"title": "Macierz pending, MSIE i MIE",
|
||||
"idea_tex": "to samo źródło, dwie niezależne bramki",
|
||||
"priority": "kluczowe",
|
||||
"key": true,
|
||||
"prompt_tex": "Wypełnij trzy wiersze: pending=1 z samym MIE, pending=1 z samym MSIE oraz pending=1 z obiema bramkami. Przewidź licznik ISR i końcowy pending.",
|
||||
"criterion": "Hazard3: pending=1, blocked_no_msie=1, blocked_no_mie=1, delivered_both=1, count=1, mcause=0x80000003, pending_after=0, pass=1 i kod 0.",
|
||||
"evidence_tex": "Tabela prawdy dwóch bramek dla jednego utrzymywanego pending, licznik ISR, końcowy clear, mret i kod wyjścia Hazard3.",
|
||||
"worksheet_step2": "Macierz pending/MSIE/MIE",
|
||||
"worksheet_step3": "Dostarczenie, clear i kod wyjścia",
|
||||
"viewpoints": [
|
||||
{"id":"A1","status":"enabled","title":"CONTEXT — jedna zmienna, dwie kontrolki","content_tex":"Bodziec MSIP pozostaje ten sam podczas dwóch prób blokowanych i próby dostarczonej. Przykład zmienia wyłącznie bramki rdzenia, więc nie myli nowego zdarzenia z nową konfiguracją."},
|
||||
{"id":"A2","status":"enabled","title":"STRUCTURE — macierz 1×2×2","content_tex":"Oś danych to pending=1. Dwie osie sterujące to MSIE i MIE. Cztery kombinacje mają jeden stan dostarczalny: oba bity 1. Przykład mierzy trzy istotne wiersze przy utrzymanym pending."},
|
||||
{"id":"A3","status":"enabled","title":"DISPATCH — wejście dopiero dla 1/1","content_tex":"Sprzętowy dispatch do vector 3 nie zachodzi przy żadnej pojedynczej otwartej bramce. Dopiero MSIE=1 i MIE=1 pozwalają utworzyć trap, zapisać cause i wejść do ISR kończącego się mret."},
|
||||
{"id":"A4","status":"enabled","title":"APPLICATION — dwa razy blocked, raz delivered","content_tex":"Przy MIE=1/MSIE=0 licznik zostaje 0. Przy MIE=0/MSIE=1 również zostaje 0. Przy obu równych 1 rośnie dokładnie do 1, mcause ma wartość 0x80000003, a clear zeruje pending."},
|
||||
{"id":"A5","status":"enabled","title":"FLOW — nie zmieniaj źródła między próbami","content_tex":"Program podnosi MSIP raz, następnie testuje global-only, individual-only i both. Globalny bit jest zamykany przed zmianą MSIE, aby dostarczenie nie zaszło między pomiarem a zapisaniem wyniku."},
|
||||
{"id":"A6","status":"enabled","title":"STATE — P10, P01, P11, CLEAR","content_tex":"Skrót \\texttt{Pxy} oznacza pending=1, MSIE=x, MIE=y. Ślad to \\texttt{P01(blocked) -> P10(blocked) -> P11(active) -> CLEAR}. Licznik zmienia się tylko na trzeciej krawędzi."},
|
||||
{"id":"A7","status":"enabled","title":"RUNTIME — odczyt mip, zapisy mie/mstatus","content_tex":"Raport utrwala trzy decyzje i cause. Listing rozdziela \\texttt{csrs/csrc mie}, \\texttt{csrs/csrc mstatus} oraz odczyt mip. Objdump niezależnie potwierdza mret w ISR."},
|
||||
{"id":"A8","status":"enabled","title":"PATTERNS — source, individual, global gate","content_tex":"Trzywarstwowy model zapobiega typowemu błędowi: pending nie znaczy delivered. Ten sam wzorzec wróci dla MTIP/MTIE oraz external IRQ z enable peryferium, kontrolera i globalnym MIE."}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
OUTPUT_FORMAT("elf32-littleriscv")
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY { RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 16M }
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5);
|
||||
data PT_LOAD FLAGS(6);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = ORIGIN(RAM);
|
||||
.text : ALIGN(4)
|
||||
{
|
||||
KEEP(*(.vectors))
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text .text.*)
|
||||
} > RAM :text
|
||||
.rodata : ALIGN(4) { *(.rodata .rodata.*) } > RAM :text
|
||||
.data : ALIGN(16)
|
||||
{
|
||||
__data_start = .;
|
||||
*(.data .data.*)
|
||||
*(.sdata .sdata.*)
|
||||
__data_end = .;
|
||||
} > RAM :data
|
||||
.bss (NOLOAD) : ALIGN(16)
|
||||
{
|
||||
__bss_start = .;
|
||||
*(.bss .bss.* COMMON)
|
||||
*(.sbss .sbss.*)
|
||||
__bss_end = .;
|
||||
} > RAM :data
|
||||
. = ALIGN(16);
|
||||
_end = .;
|
||||
PROVIDE(end = .);
|
||||
__stack_top = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__stack_reserve = 64K;
|
||||
__stack_bottom = __stack_top - __stack_reserve;
|
||||
__global_pointer$ = __data_start + 0x800;
|
||||
/DISCARD/ : { *(.comment) *(.note .note.*) }
|
||||
}
|
||||
|
||||
ASSERT(_end <= __stack_bottom,
|
||||
"C10: program overlaps the reserved 64 KiB stack")
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd)
|
||||
repo_root=$(CDPATH= cd "$script_dir/.." && pwd)
|
||||
layouts_root=$repo_root/../../../tools/card-layouts
|
||||
python3 "$layouts_root/tools/build_kr_c_card.py" "$repo_root"
|
||||
exec python3 "$layouts_root/tools/render_card.py" "$repo_root" "$@"
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd)
|
||||
repo_root=$(CDPATH= cd "$script_dir/.." && pwd)
|
||||
layouts_root=$repo_root/../../../tools/card-layouts
|
||||
|
||||
if ! git -C "$repo_root" rev-parse --verify HEAD >/dev/null 2>&1; then
|
||||
export GITEA_SHA=0000000000000000000000000000000000000000
|
||||
fi
|
||||
|
||||
exec "$layouts_root/tools/render_card_pdf_preserving.sh" "$repo_root"
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifndef C10_COMMON_H
|
||||
#define C10_COMMON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hazard3_csr.h"
|
||||
#include "tb_cxxrtl_io.h"
|
||||
|
||||
#define MSTATUS_MIE UINT32_C(0x00000008)
|
||||
#define MIE_MSIE UINT32_C(0x00000008)
|
||||
#define MIP_MSIP UINT32_C(0x00000008)
|
||||
#define MACHINE_ECALL_CAUSE UINT32_C(0x0000000b)
|
||||
#define MACHINE_SOFTWARE_IRQ_CAUSE UINT32_C(0x80000003)
|
||||
|
||||
static inline void c10_global_irq_enable(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
set_csr(mstatus, MSTATUS_MIE);
|
||||
else
|
||||
clear_csr(mstatus, MSTATUS_MIE);
|
||||
}
|
||||
|
||||
static inline void c10_software_irq_enable(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
set_csr(mie, MIE_MSIE);
|
||||
else
|
||||
clear_csr(mie, MIE_MSIE);
|
||||
}
|
||||
|
||||
static inline void c10_disable_interrupts(void)
|
||||
{
|
||||
c10_global_irq_enable(false);
|
||||
c10_software_irq_enable(false);
|
||||
tb_clr_softirq(0);
|
||||
}
|
||||
|
||||
static inline void c10_settle(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < 32u; ++i)
|
||||
__asm__ volatile("nop");
|
||||
}
|
||||
|
||||
static inline bool c10_wait_for(volatile uint32_t *value, uint32_t expected)
|
||||
{
|
||||
for (uint32_t i = 0; i < 100000u; ++i) {
|
||||
if (*value == expected)
|
||||
return true;
|
||||
__asm__ volatile("wfi");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void c10_report(const char *label, uint32_t value)
|
||||
{
|
||||
tb_puts(label);
|
||||
tb_put_u32(value);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "c10_common.h"
|
||||
|
||||
volatile uint32_t g_task01_count;
|
||||
volatile uint32_t g_task01_mcause;
|
||||
volatile uint32_t g_task01_mepc;
|
||||
volatile uint32_t g_task01_resume_pc;
|
||||
volatile uint32_t g_task01_resumed;
|
||||
volatile uint32_t g_task01_pass;
|
||||
|
||||
void __attribute__((interrupt("machine"))) handle_exception(void)
|
||||
{
|
||||
const uint32_t cause = read_csr(mcause);
|
||||
const uint32_t pc = read_csr(mepc);
|
||||
|
||||
g_task01_count++;
|
||||
g_task01_mcause = cause;
|
||||
g_task01_mepc = pc;
|
||||
g_task01_resume_pc = pc + 4u;
|
||||
write_csr(mepc, g_task01_resume_pc);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
c10_disable_interrupts();
|
||||
__asm__ volatile("ecall");
|
||||
g_task01_resumed = 1u;
|
||||
|
||||
g_task01_pass = g_task01_count == 1u &&
|
||||
g_task01_mcause == MACHINE_ECALL_CAUSE &&
|
||||
g_task01_resume_pc - g_task01_mepc == 4u &&
|
||||
g_task01_resumed == 1u;
|
||||
|
||||
c10_report("T01 count=", g_task01_count);
|
||||
c10_report("T01 mcause=", g_task01_mcause);
|
||||
c10_report("T01 mepc=", g_task01_mepc);
|
||||
c10_report("T01 resume_pc=", g_task01_resume_pc);
|
||||
c10_report("T01 delta=", g_task01_resume_pc - g_task01_mepc);
|
||||
c10_report("T01 resumed=", g_task01_resumed);
|
||||
c10_report("T01 pass=", g_task01_pass);
|
||||
return g_task01_pass ? 0 : 1;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "c10_common.h"
|
||||
|
||||
volatile uint32_t g_task02_count;
|
||||
volatile uint32_t g_task02_mcause;
|
||||
volatile uint32_t g_task02_pending_in_handler;
|
||||
volatile uint32_t g_task02_pending_before_enable;
|
||||
volatile uint32_t g_task02_pending_after;
|
||||
volatile uint32_t g_task02_resumed;
|
||||
volatile uint32_t g_task02_pass;
|
||||
|
||||
void __attribute__((interrupt("machine"))) isr_machine_softirq(void)
|
||||
{
|
||||
g_task02_mcause = read_csr(mcause);
|
||||
g_task02_pending_in_handler =
|
||||
(read_csr(mip) & MIP_MSIP) != 0u ? 1u : 0u;
|
||||
tb_clr_softirq(0);
|
||||
g_task02_count++;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
c10_disable_interrupts();
|
||||
c10_software_irq_enable(true);
|
||||
tb_set_softirq(0);
|
||||
c10_settle();
|
||||
g_task02_pending_before_enable =
|
||||
(read_csr(mip) & MIP_MSIP) != 0u ? 1u : 0u;
|
||||
|
||||
c10_global_irq_enable(true);
|
||||
const bool handled = c10_wait_for(&g_task02_count, 1u);
|
||||
g_task02_resumed = 1u;
|
||||
|
||||
c10_global_irq_enable(false);
|
||||
c10_settle();
|
||||
g_task02_pending_after =
|
||||
(read_csr(mip) & MIP_MSIP) != 0u ? 1u : 0u;
|
||||
c10_software_irq_enable(false);
|
||||
|
||||
g_task02_pass = handled &&
|
||||
g_task02_count == 1u &&
|
||||
g_task02_mcause == MACHINE_SOFTWARE_IRQ_CAUSE &&
|
||||
g_task02_pending_in_handler == 1u &&
|
||||
g_task02_pending_before_enable == 1u &&
|
||||
g_task02_pending_after == 0u &&
|
||||
g_task02_resumed == 1u;
|
||||
|
||||
c10_report("T02 count=", g_task02_count);
|
||||
c10_report("T02 mcause=", g_task02_mcause);
|
||||
c10_report("T02 pending_before=", g_task02_pending_before_enable);
|
||||
c10_report("T02 pending_in_handler=", g_task02_pending_in_handler);
|
||||
c10_report("T02 pending_after=", g_task02_pending_after);
|
||||
c10_report("T02 resumed=", g_task02_resumed);
|
||||
c10_report("T02 pass=", g_task02_pass);
|
||||
return g_task02_pass ? 0 : 1;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "c10_common.h"
|
||||
|
||||
volatile uint32_t g_task03_count;
|
||||
volatile uint32_t g_task03_mcause;
|
||||
volatile uint32_t g_task03_pending_asserted;
|
||||
volatile uint32_t g_task03_blocked_without_msie;
|
||||
volatile uint32_t g_task03_blocked_without_mie;
|
||||
volatile uint32_t g_task03_delivered_with_both;
|
||||
volatile uint32_t g_task03_pending_after;
|
||||
volatile uint32_t g_task03_pass;
|
||||
|
||||
void __attribute__((interrupt("machine"))) isr_machine_softirq(void)
|
||||
{
|
||||
g_task03_mcause = read_csr(mcause);
|
||||
tb_clr_softirq(0);
|
||||
g_task03_count++;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
c10_disable_interrupts();
|
||||
tb_set_softirq(0);
|
||||
c10_settle();
|
||||
g_task03_pending_asserted =
|
||||
(read_csr(mip) & MIP_MSIP) != 0u ? 1u : 0u;
|
||||
|
||||
c10_global_irq_enable(true);
|
||||
c10_settle();
|
||||
g_task03_blocked_without_msie = g_task03_count == 0u ? 1u : 0u;
|
||||
|
||||
c10_global_irq_enable(false);
|
||||
c10_software_irq_enable(true);
|
||||
c10_settle();
|
||||
g_task03_blocked_without_mie = g_task03_count == 0u ? 1u : 0u;
|
||||
|
||||
c10_global_irq_enable(true);
|
||||
g_task03_delivered_with_both = c10_wait_for(&g_task03_count, 1u) ? 1u : 0u;
|
||||
|
||||
c10_global_irq_enable(false);
|
||||
c10_settle();
|
||||
g_task03_pending_after =
|
||||
(read_csr(mip) & MIP_MSIP) != 0u ? 1u : 0u;
|
||||
c10_software_irq_enable(false);
|
||||
|
||||
g_task03_pass = g_task03_pending_asserted == 1u &&
|
||||
g_task03_blocked_without_msie == 1u &&
|
||||
g_task03_blocked_without_mie == 1u &&
|
||||
g_task03_delivered_with_both == 1u &&
|
||||
g_task03_count == 1u &&
|
||||
g_task03_mcause == MACHINE_SOFTWARE_IRQ_CAUSE &&
|
||||
g_task03_pending_after == 0u;
|
||||
|
||||
c10_report("T03 pending=", g_task03_pending_asserted);
|
||||
c10_report("T03 blocked_no_msie=", g_task03_blocked_without_msie);
|
||||
c10_report("T03 blocked_no_mie=", g_task03_blocked_without_mie);
|
||||
c10_report("T03 delivered_both=", g_task03_delivered_with_both);
|
||||
c10_report("T03 count=", g_task03_count);
|
||||
c10_report("T03 mcause=", g_task03_mcause);
|
||||
c10_report("T03 pending_after=", g_task03_pending_after);
|
||||
c10_report("T03 pass=", g_task03_pass);
|
||||
return g_task03_pass ? 0 : 1;
|
||||
}
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
tmp_dir="$(mktemp -d /tmp/c10-card.XXXXXX)"
|
||||
cleanup() {
|
||||
rm -rf -- "$tmp_dir"
|
||||
}
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
"$root/scripts/render_card_layouts.sh" >/dev/null
|
||||
"$root/scripts/render_new_pdf.sh" >/dev/null
|
||||
|
||||
pdf="$(find "$root/doc/pdf" -maxdepth 1 -type f \
|
||||
-name 'mpabi-inf-c-10-traps-interrupt-control-*.pdf' -print -quit)"
|
||||
test -n "$pdf"
|
||||
qpdf --check "$pdf" >/dev/null
|
||||
pdftotext -layout "$pdf" "$tmp_dir/card.txt"
|
||||
|
||||
blocks="$(rg -o 'A[1-8] (CONTEXT|STRUCTURE|DISPATCH|APPLICATION|FLOW|STATE|RUNTIME|PATTERNS)' \
|
||||
"$tmp_dir/card.txt" | wc -l)"
|
||||
test "$blocks" -eq 24
|
||||
|
||||
if awk 'BEGIN { RS="\f" } { compact=$0; gsub(/[[:space:]]/, "", compact); if (length(compact) < 100) exit 1 }' \
|
||||
"$tmp_dir/card.txt"; then
|
||||
:
|
||||
else
|
||||
echo "FAIL: empty or nearly empty PDF page" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if awk 'BEGIN { RS="\f" } \
|
||||
/A[1-8] (CONTEXT|STRUCTURE|DISPATCH|APPLICATION|FLOW|STATE|RUNTIME|PATTERNS)/ && !/TASK0[1-3]/ { exit 1 }' \
|
||||
"$tmp_dir/card.txt"; then
|
||||
:
|
||||
else
|
||||
echo "FAIL: A1-A8 block on a page without its TASK heading" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
jq -e '
|
||||
.tasks_order == ["task01", "task02", "task03"] and
|
||||
all(.tasks[];
|
||||
[.viewpoints[].id] == ["A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"] and
|
||||
all(.viewpoints[]; .status == "enabled" or .status == "unavailable"))
|
||||
' "$root/json/card_source.json" >/dev/null
|
||||
node --check "$root/web/app.js"
|
||||
|
||||
printf 'PASS card: 3 tasks, 24 A blocks, valid PDF, no empty/anonymous page\n'
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
env_root="${RV_ENV_ROOT:-/home/user/dev/edu/rv32i-hazard3-student-env}"
|
||||
tb="${HAZARD3_TB:-$env_root/vendor/Hazard3/test/sim/tb_verilator/tb}"
|
||||
objdump="${RISCV_PREFIX:-riscv64-unknown-elf-}objdump"
|
||||
|
||||
make -C "$root" -s tasks "RV_ENV_ROOT=$env_root"
|
||||
|
||||
run_task() {
|
||||
local task="$1"
|
||||
shift
|
||||
local log="$root/build/$task/oracle.log"
|
||||
"$tb" --bin "$root/build/$task/prog.bin" --cycles 500000 --cpuret --logfile "$log"
|
||||
grep -Fqx 'CPU requested halt. Exit code 0' "$log"
|
||||
local expected
|
||||
for expected in "$@"; do
|
||||
grep -Fqx "$expected" "$log" || {
|
||||
printf 'FAIL %s missing <%s>\n' "$task" "$expected" >&2
|
||||
sed -n '1,160p' "$log" >&2
|
||||
return 1
|
||||
}
|
||||
done
|
||||
printf 'PASS Hazard3 oracle: %s\n' "$task"
|
||||
}
|
||||
|
||||
run_task task01_ecall_resume \
|
||||
'T01 count=00000001' \
|
||||
'T01 mcause=0000000b' \
|
||||
'T01 delta=00000004' \
|
||||
'T01 resumed=00000001' \
|
||||
'T01 pass=00000001'
|
||||
|
||||
run_task task02_machine_software_irq \
|
||||
'T02 count=00000001' \
|
||||
'T02 mcause=80000003' \
|
||||
'T02 pending_before=00000001' \
|
||||
'T02 pending_in_handler=00000001' \
|
||||
'T02 pending_after=00000000' \
|
||||
'T02 resumed=00000001' \
|
||||
'T02 pass=00000001'
|
||||
|
||||
run_task task03_pending_enable_matrix \
|
||||
'T03 pending=00000001' \
|
||||
'T03 blocked_no_msie=00000001' \
|
||||
'T03 blocked_no_mie=00000001' \
|
||||
'T03 delivered_both=00000001' \
|
||||
'T03 count=00000001' \
|
||||
'T03 mcause=80000003' \
|
||||
'T03 pending_after=00000000' \
|
||||
'T03 pass=00000001'
|
||||
|
||||
for pair in 'task01_ecall_resume handle_exception' \
|
||||
'task02_machine_software_irq isr_machine_softirq' \
|
||||
'task03_pending_enable_matrix isr_machine_softirq'; do
|
||||
read -r task symbol <<<"$pair"
|
||||
"$objdump" -d "$root/build/$task/prog.elf" |
|
||||
sed -n "/<$symbol>:/,/^$/p" |
|
||||
grep -Eq '[[:space:]]mret$'
|
||||
done
|
||||
|
||||
t01_mepc=$(sed -n 's/^T01 mepc=//p' "$root/build/task01_ecall_resume/oracle.log")
|
||||
t01_resume=$(sed -n 's/^T01 resume_pc=//p' "$root/build/task01_ecall_resume/oracle.log")
|
||||
(( 16#$t01_resume - 16#$t01_mepc == 4 ))
|
||||
printf 'PASS independent oracle: mepc+4, pending/enable matrix, ISR mret\n'
|
||||
File diff suppressed because one or more lines are too long
+61
File diff suppressed because one or more lines are too long
+2567
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="card-renderer" content="react">
|
||||
<title>Karta pracy</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="app.css">
|
||||
</head>
|
||||
<body class="resource-header-enabled">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user