Files
2025-yatcpu/lab2/实验报告/report.tex
2025-12-21 23:11:21 +08:00

509 lines
27 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[12pt]{ctexart}
\usepackage[utf8]{inputenc}
\usepackage[margin=2.5cm]{geometry}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{hyperref}
\hypersetup{
colorlinks=true,
linkcolor=black,
citecolor=green,
urlcolor=blue,
filecolor=magenta,
pdftitle={实验二RISC-V CPU 中断处理机制设计与实现},
pdfauthor={朱梓涵},
pdfsubject={RISC-V CPU 设计与实现报告},
pdfkeywords={RISC-V, CPU, Chisel, 中断, CLINT, CSR, 实验报告}
}
\usepackage{fancyhdr}
\usepackage{enumitem}
% --- 页眉页脚设置 ---
\setlength{\headheight}{15pt}
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{\MakeUppercase{实验二RISC-V CPU 中断处理机制设计与实现}}
\fancyfoot[C]{\thepage}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt}
% --- 标题信息 ---
\title{\vspace{-2cm}\textbf{实验二RISC-V CPU 中断处理机制设计与实现}}
\author{朱梓涵 \\ 学号24325356}
\date{\today}
% --- 代码高亮风格定义 (Solarized-light) ---
\definecolor{sol-base03}{HTML}{002b36}
\definecolor{sol-base02}{HTML}{073642}
\definecolor{sol-base01}{HTML}{586e75}
\definecolor{sol-base00}{HTML}{657b83}
\definecolor{sol-base0}{HTML}{839496}
\definecolor{sol-base1}{HTML}{93a1a1}
\definecolor{sol-base2}{HTML}{eee8d5}
\definecolor{sol-base3}{HTML}{fdf6e3}
\definecolor{sol-yellow}{HTML}{b58900}
\definecolor{sol-orange}{HTML}{cb4b16}
\definecolor{sol-red}{HTML}{dc322f}
\definecolor{sol-magenta}{HTML}{d33682}
\definecolor{sol-violet}{HTML}{6c71c4}
\definecolor{sol-blue}{HTML}{268bd2}
\definecolor{sol-cyan}{HTML}{2aa198}
\definecolor{sol-green}{HTML}{859900}
\lstdefinestyle{ScalaChiselStyle}{commentstyle=\color{sol-base01}\itshape,keywordstyle=\color{sol-green}\bfseries,stringstyle=\color{sol-cyan},basicstyle=\ttfamily\small,breakatwhitespace=false,breaklines=true,captionpos=b,keepspaces=true,numbers=none,showspaces=false,showstringspaces=false,showtabs=false,tabsize=2,frame=single,rulecolor=\color{black},morekeywords={when, Mux, MuxLookup, IndexedSeq, U, io, :=, object, val, def, class, override, package, import, extends, with, Bits, UInt, SInt},extendedchars=false,literate={:}{{\color{sol-base02}:}}1}
\lstdefinestyle{CStyle}{commentstyle=\color{sol-base01}\itshape,keywordstyle=\color{sol-orange}\bfseries,stringstyle=\color{sol-cyan},basicstyle=\ttfamily\small,breakatwhitespace=false,breaklines=true,captionpos=b,keepspaces=true,numbers=none,showspaces=false,showstringspaces=false,showtabs=false,tabsize=2,frame=single,rulecolor=\color{black},extendedchars=false}
\lstset{style=ScalaChiselStyle}
% --- 图片计数器与章节联动 ---
\counterwithin{figure}{section}
\counterwithin{table}{section}
% --- 文档开始 ---
\begin{document}
\maketitle
\thispagestyle{empty}
\section{实验目的}
本实验旨在为已实现的单周期 RISC-V CPU 增加中断与异常处理功能,深入理解现代处理器如何响应并处理非顺序控制流事件。实验目标包括:
\begin{enumerate}[label=\arabic*.]
\item 设计并实现控制状态寄存器模块,支持 CSR 指令的读写操作。
\item 设计并实现核本地中断控制器,使其能够正确处理外部硬件中断和内部软件中断以及中断返回指令。
\item 理解中断处理流程中 \texttt{mstatus}, \texttt{mepc}, \texttt{mcause}, \texttt{mtvec} 等关键寄存器的作用与变化。
\item 学习通过 Chisel 测试用例和波形图分析,验证复杂的中断处理逻辑的正确性。
\end{enumerate}
\section{实验环境}
\begin{itemize}
\item \textbf{操作系统}: Windows 11
\item \textbf{开发工具}: IntelliJ IDEA
\item \textbf{构建工具}: SBT
\item \textbf{仿真与测试}: Verilator, GTKWave, MSYS2
\end{itemize}
\section{模块实现与分析}
本次实验的核心是新增 \texttt{CSR}\texttt{CLINT} 模块,并对 \texttt{Execute} 模块进行扩展以支持 CSR 指令。
\subsection{CSR 模块}
CSR 模块是 CPU 的状态管理中心,负责存储和更新如 \texttt{mstatus}, \texttt{mepc} 等关键状态寄存器。
\begin{itemize}
\item \textbf{实现要点}
\begin{enumerate}
\item \textbf{独立寄存器与查找表}:将重要的 CSR\texttt{mstatus})实现为独立的物理寄存器,并通过一个查找表 \texttt{regLUT} 响应读请求,设计清晰且高效。
\item \textbf{写操作优先级}:写入逻辑必须处理来自 CLINT中断/异常事件)和 ExecuteCSR指令的并发写请求。设计中CLINT 的写入拥有最高优先级,确保了中断处理的原子性。
\item \textbf{数据旁路}为解决数据冒险设计了旁路机制。CSR 模块会预计算出下一拍寄存器的值并立即提供给 CLINT使其能在当前周期就基于最新的 CPU 状态做出正确决策。
\end{enumerate}
\end{itemize}
\subsubsection{代码实现}
\begin{lstlisting}[caption={CSR 模块的写入优先级与旁路逻辑}, label={lst:csr_logic}]
val mstatus_next = Mux(io.reg_write_enable_id &&
io.reg_write_address_id === CSRRegister.MSTATUS,
io.reg_write_data_ex, mstatus)
val mepc_next = Mux(io.reg_write_enable_id &&
io.reg_write_address_id === CSRRegister.MEPC,
io.reg_write_data_ex, mepc)
io.clint_access_bundle.mstatus := mstatus_next
io.clint_access_bundle.mepc := mepc_next
when(io.clint_access_bundle.direct_write_enable) {
mstatus := io.clint_access_bundle.mstatus_write_data
mepc := io.clint_access_bundle.mepc_write_data
mcause := io.clint_access_bundle.mcause_write_data
}.elsewhen(io.reg_write_enable_id) {
when(io.reg_write_address_id === CSRRegister.MSTATUS) {
mstatus := io.reg_write_data_ex
}
}
\end{lstlisting}
\subsection{CLINT 模块}
CLINT 是中断处理的决策中心,负责监视 CPU 状态,判断中断与异常事件,并生成控制信号来改变 CPU 的执行流和状态。
\begin{itemize}
\item \textbf{实现要点}
\begin{enumerate}
\item \textbf{事件检测}:通过组合逻辑判断外部中断信号 (\texttt{interrupt\_flag}) 和特定指令(\texttt{mret}, \texttt{ecall}, \texttt{ebreak})的发生。
\item \textbf{状态更新计算}:根据发生的事件类型,精确计算 \texttt{mepc}, \texttt{mcause}, \texttt{mstatus} 这三个 CSR 寄存器需要更新成的新值。
\item \textbf{PC 重定向}:当陷阱 (trap) 发生或 \texttt{mret} 执行时,置位 \texttt{interrupt\_assert} 标志,并提供新的 PC 地址(中断时为 \texttt{mtvec},返回时为 \texttt{mepc})。
\item \textbf{处理优先级}:通过一个 \texttt{when-elsewhen-otherwise} 结构明确了事件处理的优先级:外部硬件中断 > \texttt{mret} > \texttt{ecall} > \texttt{ebreak}
\end{enumerate}
\end{itemize}
\subsubsection{代码实现}
\begin{lstlisting}[caption={CLINT 模块处理硬件中断的核心逻辑}, label={lst:clint_logic}]
val interrupt_enable = io.csr_bundle.mstatus(3)
val instruction_address = Mux(
io.jump_flag,
io.jump_address,
io.instruction_address + 4.U
)
val mstatus = io.csr_bundle.mstatus
val mie = mstatus(3)
when(io.interrupt_flag =/= InterruptCode.None && interrupt_enable) {
io.interrupt_assert := true.B
io.csr_bundle.direct_write_enable := true.B
io.interrupt_handler_address := io.csr_bundle.mtvec
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := "h80000007".U
val new_mpie = mie << 7
io.csr_bundle.mstatus_write_data :=
(mstatus & (~(1.U << 3)).asUInt) | new_mpie | (3.U << 11)
}.elsewhen(io.instruction === InstructionsRet.mret) {
}
\end{lstlisting}
\section{测试与结果分析}
\subsection{CLINTCSRTest: 硬件中断测试分析}
\subsubsection{测试机制简述}
该测试旨在验证 CPU 对外部硬件中断的响应是否正确。测试用例通过 \texttt{chiseltest} 框架,模拟外部定时器中断信号,并验证 CLINT 模块在不同场景下的中断处理行为。
\textbf{输入信号:}
\begin{itemize}
\item \texttt{interrupt\_flag}: 外部中断标志,测试中使用值为 \texttt{0x1} 的定时器中断
\item \texttt{instruction}: 当前执行的指令
\item \texttt{instruction\_address}: 当前指令地址,表示被中断时的 PC 值
\item \texttt{jump\_flag}: 指示当前指令是否为跳转指令
\item \texttt{jump\_address}: 跳转目标地址
\item \texttt{csr\_bundle.mtvec}: 预设的中断向量表基地址 \texttt{0x1144}
\item \texttt{csr\_bundle.mstatus}: 初始值 \texttt{0x1888}MIE=1, MPIE=1使能中断
\end{itemize}
\textbf{测试的 CLINT 功能:}
\begin{enumerate}
\item \textbf{中断检测}:检测外部中断信号 (\texttt{interrupt\_flag}) 并判断是否应该响应(检查 \texttt{mstatus.MIE} 位)
\item \textbf{上下文保存}:将中断发生时的关键状态保存到 CSR 寄存器:
\begin{itemize}
\item \texttt{MEPC} $\leftarrow$ PC + 4非跳转或跳转目标地址跳转
\item \texttt{MCAUSE} $\leftarrow$ 中断原因编码(\texttt{0x80000007} 表示定时器中断)
\item \texttt{MSTATUS} $\leftarrow$ 更新状态MIE $\leftarrow$ 0, MPIE $\leftarrow$ 原 MIE 值)
\end{itemize}
\item \textbf{中断跳转}:跳转到中断处理程序(\texttt{mtvec} 中存储的地址 \texttt{0x1144}
\item \textbf{中断返回}:执行 \texttt{mret} 指令时恢复现场PC $\leftarrow$ \texttt{MEPC}MIE $\leftarrow$ MPIE
\item \textbf{跳转与非跳转指令的差异}:验证在跳转指令执行期间发生中断时,\texttt{MEPC} 保存的是跳转目标地址而非 PC + 4
\end{enumerate}
\subsubsection{波形图分析:非跳转指令下的硬件中断处理}
本次测试选用 \texttt{CLINTCSRTest.scala} 中的硬件中断测试(\texttt{handle external interrupt})。测试通过手动向 CPU 输入一个外部硬件中断标志 \texttt{io\_interrupt\_flag},并观察 CLINT 是否正确生成中断、是否能在非跳转指令下按照 RISC-V 标准流程完成一次完整的中断处理。
\textbf{测试输入信号及作用:}
\begin{table}[htbp]
\centering
\begin{tabular}{|l|p{8cm}|}
\hline
\textbf{信号} & \textbf{作用} \\
\hline
\texttt{io\_interrupt\_flag = 1} & 触发一次硬件中断(定时器中断) \\
\hline
\texttt{io\_instruction = 0x13} & 当前执行指令NOP0x00000013 \\
\hline
\texttt{io\_instruction\_address = 0x1900} & 当前 PC 值 \\
\hline
\texttt{io\_jump\_flag = 0} & 非跳转指令标志 \\
\hline
\texttt{mtvec}\texttt{mstatus} 初始写入 & 配置中断入口0x1144及打开 MIE \\
\hline
\end{tabular}
\caption{硬件中断测试输入信号}
\end{table}
此测试用来验证 CLINT 是否能完成以下功能:
\begin{itemize}
\item 在非跳转指令下正确响应硬件中断
\item 正确生成中断断点(\texttt{mepc = PC + 4}
\item 正确写入中断原因(\texttt{mcause = 0x80000007}
\item 自动清除 MIE 并保存到 MPIE\texttt{mstatus} 更新)
\item 正确跳转到中断处理入口(\texttt{mtvec}
\end{itemize}
\begin{figure}[htbp]
\centering
\includegraphics[width=\textwidth]{1.png}
\caption{硬件中断处理过程波形图 - 非跳转指令场景8ps $\sim$ 12ps}
\label{fig:external_interrupt_waveform}
\end{figure}
\textbf{波形图关键信号说明:}
\begin{itemize}
\item \texttt{io\_interrupt\_flag[31:0]}: 外部中断标志输入
\item \texttt{io\_instruction[31:0]}: 当前执行的指令
\item \texttt{io\_instruction\_address[31:0]}: 当前指令地址PC
\item \texttt{io\_jump\_flag}: 跳转指令标志
\item \texttt{io\_jump\_address[31:0]}: 跳转目标地址
\item \texttt{io\_interrupt\_assert}: CLINT 输出的中断响应信号
\item \texttt{io\_interrupt\_handler\_address[31:0]}: 中断跳转目标地址
\item \texttt{mtvec[31:0]}: 中断向量表基地址
\item \texttt{mepc[31:0]}: 中断返回地址
\item \texttt{mcause[31:0]}: 中断原因寄存器
\item \texttt{mstatus[31:0]}: 机器状态寄存器
\end{itemize}
如图所示,本测试一次完整的硬件中断处理过程(波形截图区间约为 8ps $\sim$ 12ps。以下挑选关键信号说明中断发生与处理的整个过程
\paragraph{(1) 初始化阶段(约 6ps}
在中断发生前,测试代码已通过 CSR 写指令完成初始化:
\begin{itemize}
\item \texttt{mtvec = 0x00001144}:中断处理程序入口地址已配置
\item \texttt{mstatus = 0x00001888}:全局中断已使能
\begin{itemize}
\item 二进制表示为 \texttt{...0001\_1000\_1000\_1000}
\item bit[3] MIE = 1全局中断使能
\item bit[7] MPIE = 1中断前的 MIE 备份)
\end{itemize}
\end{itemize}
\paragraph{(2) 中断发生时刻(约 9ps}
此时 CPU 正在执行一条普通的 NOP 指令,外部中断请求到来:
\begin{itemize}
\item \texttt{io\_instruction\_address = 0x00001900}:当前 PC
\item \texttt{io\_instruction = 0x00000013}NOP 指令
\item \texttt{io\_jump\_flag = 0}:非跳转指令
\item \texttt{io\_interrupt\_flag}:从 \texttt{0x00000000} $\rightarrow$ \texttt{0x00000001}Timer0 中断)
\end{itemize}
\paragraph{(3) 同周期中断响应(约 9ps}
CLINT 模块检测到 \texttt{interrupt\_flag = 1}\texttt{mstatus.MIE = 1} 后,立即通过组合逻辑响应中断:
\begin{itemize}
\item \texttt{io\_interrupt\_assert = 1}:触发中断信号
\item \texttt{io\_interrupt\_handler\_address = 0x00001144}:指示 CPU 跳转到 \texttt{mtvec}
\item 波形图上可观察到 \texttt{io\_interrupt\_assert} 出现一个脉冲
\item \texttt{io\_interrupt\_handler\_address} 短暂输出 \texttt{0x1144} 后恢复为 \texttt{0}
\end{itemize}
这表示 CPU 将在下一时钟周期跳转到中断处理程序入口。
\paragraph{(4) CSR 自动更新(约 10ps}
在时钟上升沿CSR 模块根据 CLINT 的 \texttt{direct\_write\_enable} 信号自动更新关键寄存器:
\begin{itemize}
\item \texttt{mepc}:从 \texttt{0x00000000} $\rightarrow$ \texttt{0x00001904}
\begin{itemize}
\item 保存的是 PC + 4\texttt{0x1900 + 4 = 0x1904}
\item 这是被中断指令的下一条指令地址,中断返回后将从此处继续执行
\end{itemize}
\item \texttt{mcause}:从 \texttt{0x00000000} $\rightarrow$ \texttt{0x80000007}
\begin{itemize}
\item bit[31] = 1表示这是异步硬件中断而非同步异常
\item 低位 = 7对应 Timer 中断编码
\end{itemize}
\item \texttt{mstatus}:从 \texttt{0x00001888} $\rightarrow$ \texttt{0x00001880}
\begin{itemize}
\item \texttt{0x1888} = \texttt{...0001\_1000\_1000\_1000}MIE=1, MPIE=1
\item \texttt{0x1880} = \texttt{...0001\_1000\_1000\_0000}MIE=0, MPIE=1
\item MIE 被清 0关闭全局中断防止中断嵌套
\item MPIE 保存了先前的 MIE 值(=1
\end{itemize}
\end{itemize}
这些变化完全符合 RISC-V 特权架构手册中定义的中断进入流程。
\paragraph{(5) 中断标志清除(约 12ps 后)}
波形图显示 \texttt{io\_interrupt\_flag} 在约 12ps 后从 \texttt{1} 恢复为 \texttt{0},这是测试代码模拟中断处理程序清除外设中断标志的行为。
\vspace{1em}
\noindent\textbf{波形分析总结:}
通过以上波形图分析,可以验证 CLINT 模块在非跳转指令场景下正确实现了以下功能:
\begin{itemize}
\item \texttt{mepc} 正确保存了 PC + 4\texttt{0x1904}),确保中断返回后从下一条指令继续执行
\item \texttt{mcause} 正确记录了中断原因(\texttt{0x80000007}bit[31]=1 标识为异步中断
\item \texttt{mstatus} 自动完成 MIE 清零和 MPIE 备份,实现中断嵌套保护机制
\item 从中断检测到 CSR 更新的整个过程由硬件自动完成,无需软件干预
\end{itemize}
测试还包括跳转指令场景的验证:当 \texttt{jump\_flag=1}, \texttt{jump\_address=0x1990} 时发生中断,\texttt{mepc} 应保存跳转目标 \texttt{0x1990} 而非 \texttt{PC+4},且 \texttt{mcause=0x8000000B}。这确保了 CLINT 能正确处理各种执行场景下的中断。
\subsection{CPUTest: SimpleTrapTest 分析}
\subsubsection{测试目的}
本测试通过执行 \texttt{csrc/simpletest.c} 中的测试程序,验证 CPU 是否能够按照 RISC-V 标准正确处理中断,包括中断触发、保存现场、跳转到中断处理程序、执行处理逻辑以及返回主程序等完整流程。
\subsubsection{测试程序的中断验证机制}
\texttt{simpletest.c} 通过以下过程验证 CPU 的中断处理正确性:
\begin{lstlisting}[style=CStyle, caption={simpletest.c 测试程序源码}]
extern void enable_interrupt();
void trap_handler(void *epc, unsigned int cause){
*((int*)0x4) = 0x2022;
}
int main(){
*((int*)0x4) = 0xDEADBEEF;
enable_interrupt();
for(;;);
}
\end{lstlisting}
\paragraph{主程序初始化阶段}
程序首先向内存地址 \texttt{0x4} 写入标记值 \texttt{0xDEADBEEF},用于表示"尚未处理中断"的初始状态。随后调用 \texttt{enable\_interrupt()} 函数配置中断环境:
\begin{itemize}
\item\texttt{trap\_handler} 的地址写入 \texttt{mtvec} 寄存器
\item 设置 \texttt{mstatus.MIE = 1},使能全局中断
\end{itemize}
\paragraph{等待中断触发}
程序进入无限循环 \texttt{for(;;)},持续等待中断到来。测试框架 \texttt{TestTopModule} 在仿真过程中通过 \texttt{io.interrupt\_flag.poke(0x1)} 向 CPU 注入外部中断请求。
\paragraph{中断处理程序执行}
当中断触发后CPU 自动跳转到 \texttt{trap\_handler} 函数。该函数执行唯一的操作:将内存地址 \texttt{0x4} 的值修改为 \texttt{0x2022}。这一修改作为中断处理程序成功执行的关键证据。
\paragraph{中断返回与验证}
\texttt{trap\_handler} 执行完毕后,通过 \texttt{mret} 指令返回主程序。测试代码随后读取内存地址 \texttt{0x4} 和相关 CSR 寄存器,验证:
\begin{itemize}
\item 内存值已从 \texttt{0xDEADBEEF} 变为 \texttt{0x2022}
\item \texttt{mstatus} 恢复为 \texttt{0x1888}(中断返回后状态)
\item \texttt{mcause} 保持 \texttt{0x80000007}(记录中断原因)
\end{itemize}
\vspace{0.5em}
\noindent 该验证机制的核心在于:若无限循环能够被中断打断,且内存值发生预期变化,则证明 CPU 确实跳转到了 \texttt{trap\_handler},中断处理程序正确执行,且 \texttt{mret} 返回机制正常工作。这种通过可观测副作用验证复杂流程的方法,是嵌入式系统测试的典型手段。
\subsubsection{波形图分析}
本实验从波形图中截取了两段关键片段,分别展示中断触发与进入处理、以及中断处理程序修改内存的核心过程。
\paragraph{(1) 中断触发与进入中断处理}
\begin{figure}[htbp]
\centering
\includegraphics[width=\textwidth]{2-1.png}
\caption{SimpleTrapTest 中断触发与进入处理过程波形图(约 2000ps}
\label{fig:simpletrap_interrupt}
\end{figure}
如图所示,展示了中断触发至 CPU 进入中断处理程序的完整时序。波形图中的关键信号及其变化如下:
\begin{itemize}
\item \texttt{io\_interrupt\_flag}: 在约 2000ps 从 \texttt{0} $\rightarrow$ \texttt{0x00000001},表示外部中断请求到来,随后恢复为 \texttt{0}
\item \texttt{io\_interrupt\_assert}: 随即产生一个脉冲,说明 CLINT 已检测到中断并产生中断响应信号
\item \texttt{mepc}: 更新为 \texttt{0x000011C4},即被中断时刻 PC 的下一条指令地址,保存了中断返回点
\item \texttt{mcause}: 被写入 \texttt{0x00000007},记录中断原因为定时器中断(外部中断编码)
\item \texttt{mstatus}: 从 \texttt{0x00001888} $\rightarrow$ \texttt{0x00001880}MIE 位bit[3]被自动清零MPIE 位bit[7])保存了先前的 MIE 值,符合 RISC-V 中断进入时的标准行为
\item \texttt{io\_pc\_debug\_read}: 从原执行地址跳转到 \texttt{0x00001050} 附近,该地址为 \texttt{mtvec} 指向的 \texttt{trap\_handler} 函数入口,随后 PC 逐条递增执行中断处理程序指令
\end{itemize}
这一段波形完整展示了中断触发、CSR 自动保存、PC 跳转到 \texttt{trap\_handler} 的全过程。
\paragraph{(2) 中断处理程序修改内存值}
\begin{figure}[htbp]
\centering
\includegraphics[width=\textwidth]{2-2.png}
\caption{SimpleTrapTest 中断处理程序修改内存标志(约 2330ps $\sim$ 2390ps}
\label{fig:simpletrap_memory}
\end{figure}
如图所示,展示了验证程序成功执行的最关键时刻。该时段内 CPU 正在执行 \texttt{trap\_handler} 函数体,波形图清晰记录了以下信号变化:
\begin{itemize}
\item \texttt{io\_bundle\_write\_enable = 1}: CPU 正在执行内存写操作
\item \texttt{io\_bundle\_address = 0x00000004}: 写入的目标地址正是 \texttt{simpletest.c} 中指定的内存地址 \texttt{0x4}
\item \texttt{io\_bundle\_write\_data = 0x00002022}: 写入的数据为 \texttt{0x2022},即 \texttt{trap\_handler} 函数中期望写入的新值
\item \texttt{mstatus}: 保持 \texttt{0x00001880}说明此时仍处于中断处理状态MIE 位为 0
\item \texttt{mcause}: 保持 \texttt{0x80000007},中断原因记录未变
\item \texttt{mepc}: 保持 \texttt{0x000011C4},中断返回地址保持不变
\item \texttt{io\_pc\_debug\_read}: 在 \texttt{trap\_handler} 函数内部的指令地址间递增,表明 CPU 正在顺序执行中断处理程序
\end{itemize}
这一瞬间表明 CPU 已成功进入 \texttt{trap\_handler},并执行了中断处理中最核心的操作——将内存地址 \texttt{0x4} 的值从 \texttt{0xDEADBEEF} 替换为 \texttt{0x2022}。这是 SimpleTrapTest 验证的直接依据,也是实验要求中明确指出的"程序成功执行"的关键信号。
\paragraph{波形分析总结}
通过以上两段波形图分析,可以验证:
\begin{itemize}
\item CPU 能够在外部中断到来时正确进入中断处理流程
\item CSR 寄存器(\texttt{mepc}\texttt{mcause}\texttt{mstatus})均按 RISC-V 标准顺序自动更新
\item PC 正确跳转到 \texttt{mtvec} 指向的 \texttt{trap\_handler} 函数
\item 中断处理函数成功执行,完成了将内存地址 \texttt{0x4} 的值从 \texttt{0xDEADBEEF} 修改为 \texttt{0x2022} 的操作
\item 测试代码后续验证了 \texttt{mret} 返回后 \texttt{mstatus} 恢复为 \texttt{0x1888},中断返回机制正常工作
\end{itemize}
综上所述,本次测试成功验证了 CPU 中断处理机制的完整性与正确性。
\subsection{CPU 与操作系统协作处理定时器中断的机制}
假设本实验设计的 CPU 上运行着一个简单的操作系统如嵌入式实时操作系统当定时器中断发生时硬件CPU 与 CLINT和软件操作系统内核将协同完成中断处理的全过程。
\subsubsection{操作系统初始化阶段}
操作系统在启动过程中,执行特权指令(如 \texttt{csrrw})来初始化中断处理机制:
\begin{itemize}
\item\texttt{mtvec} 寄存器写入中断分发程序 (interrupt dispatcher) 的入口地址
\item 配置定时器硬件,设置定时周期和中断使能位
\item 设置 \texttt{mstatus} 寄存器的 MIE 位为 1使能全局中断
\end{itemize}
\subsubsection{硬件自动响应}
定时器硬件在倒计时结束后,向 CPU 发送中断信号。CPU 的 CLINT 模块检测到该信号且 \texttt{mstatus.MIE = 1} 时,硬件自动执行以下原子操作:
\begin{enumerate}
\item\texttt{mstatus.MIE} 位的值备份到 \texttt{mstatus.MPIE} 位,然后将 \texttt{mstatus.MIE} 清零,防止中断嵌套
\item 将当前 PC 的下一条指令地址存入 \texttt{mepc} 寄存器
\item 根据中断源,在 \texttt{mcause} 寄存器中写入原因码(定时器中断为 \texttt{0x80000007}
\item 读取 \texttt{mtvec} 寄存器的值,将 PC 强制设置为该地址,跳转到中断分发程序
\end{enumerate}
\subsubsection{操作系统软件处理}
CPU 跳转到操作系统预设的中断分发程序,该程序执行以下操作:
\begin{enumerate}
\item \textbf{保存上下文}:将所有通用寄存器(\texttt{x1}$\sim$\texttt{x31})压栈,保存到内核栈中
\item \textbf{识别中断源}:读取 \texttt{mcause} 寄存器,判断中断类型
\item \textbf{分发处理}:根据中断类型调用相应的中断服务例程。对于定时器中断,调用定时器中断服务例程
\item \textbf{执行中断服务例程}:定时器中断服务例程执行核心任务:
\begin{itemize}
\item 更新系统时钟计数器
\item 检查并唤醒睡眠超时的任务
\item 执行任务调度算法,决定是否需要任务切换
\item 重新配置定时器,设置下一次中断
\end{itemize}
\item \textbf{恢复上下文}:从内核栈中恢复所有通用寄存器
\item \textbf{执行 \texttt{mret}}:返回被中断的程序
\end{enumerate}
\subsubsection{硬件恢复}
执行 \texttt{mret} 指令时CPU 硬件自动执行以下操作:
\begin{enumerate}
\item\texttt{mstatus.MPIE} 的值恢复到 \texttt{mstatus.MIE},重新使能全局中断
\item\texttt{mepc} 中保存的地址加载到 PC返回被中断的程序
\end{enumerate}
至此CPU 无缝返回到被中断的用户程序继续执行。
\section{实验结论}
本次实验,我成功地为单周期 CPU 添加了完整的中断处理功能。通过设计 CSR 和 CLINT 模块,我深入学习了 RISC-V 的特权架构和中断处理流程,对 \texttt{mstatus}, \texttt{mepc}, \texttt{mcause} 等核心 CSR 的作用有了实践层面的深刻理解。解决 Windows 环境配置难题和调试复杂中断逻辑的过程,极大地锻炼了我分析问题和解决问题的能力。通过将理论知识与硬件实现、软件测试相结合,我不仅验证了 CPU 设计的正确性,也对操作系统与硬件的交互机制有了更具体的认识,为未来更深入的系统级学习打下了坚实的基础。
\end{document}