lab4差MemoryTestF

This commit is contained in:
2025-11-18 00:55:31 +08:00
parent 525360669e
commit 464d19d647
7 changed files with 227 additions and 39 deletions

View File

@@ -60,8 +60,6 @@ class CPU extends Module {
// lab1(cpu) end

View File

@@ -44,7 +44,6 @@ class InstructionFetch extends Module {
}
// la1(InstructionFetch) end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -35,17 +35,17 @@
\@writefile{toc}{\contentsline {subsection}{\numberline {5.1}单元测试InstructionDecoderTest 分析}{6}{subsection.5.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.1}L-Type 指令测试分析}{6}{subsubsection.5.1.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.2}波形图分析}{7}{subsubsection.5.1.2}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {5.1}{\ignorespaces \texttt {L-Type} 指令 \texttt {lw x10, 32(x5)} 的译码波形图}}{7}{figure.5.1}\protected@file@percent }
\newlabel{fig:lw_decode_waveform}{{5.1}{7}{\texttt {L-Type} 指令 \texttt {lw x10, 32(x5)} 的译码波形图}{figure.5.1}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {5.1}{\ignorespaces \texttt {L-Type} 指令 \texttt {lw x3, 0(x8)} 的译码波形图}}{7}{figure.5.1}\protected@file@percent }
\newlabel{fig:lw_decode_waveform}{{5.1}{7}{\texttt {L-Type} 指令 \texttt {lw x3, 0(x8)} 的译码波形图}{figure.5.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {5.2}整体测试CPUTest (以 \texttt {FibonacciTest} 为例)}{8}{subsection.5.2}\protected@file@percent }
\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.1}\texttt {fibonacci.c} 程序分析}{8}{subsubsection.5.2.1}\protected@file@percent }
\newlabel{lst:fib_c}{{5}{8}{Fibonacci 递归程序 \texttt {fibonacci.c}}{lstlisting.5}{}}
\@writefile{lol}{\contentsline {lstlisting}{\numberline {5}Fibonacci 递归程序 \texttt {fibonacci.c}}{8}{lstlisting.5}\protected@file@percent }
\newlabel{lst:chisel_test}{{6}{8}{Chisel 测试代码片段}{lstlisting.6}{}}
\@writefile{lol}{\contentsline {lstlisting}{\numberline {6}Chisel 测试代码片段}{8}{lstlisting.6}\protected@file@percent }
\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.2}波形图分析}{9}{subsubsection.5.2.2}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {5.2}{\ignorespaces Fibonacci 程序执行末期及结果写入内存的波形图}}{9}{figure.5.2}\protected@file@percent }
\newlabel{fig:fibonacci_waveform}{{5.2}{9}{Fibonacci 程序执行末期及结果写入内存的波形图}{figure.5.2}{}}
\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.2}波形图分析}{9}{subsubsection.5.2.2}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {6}遇到的问题与改进建议}{10}{section.6}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {7}实验结论}{10}{section.7}\protected@file@percent }
\gdef \@abspage@last{10}

Binary file not shown.

View File

@@ -21,6 +21,12 @@
% 目录、交叉引用可点击生成PDF书签
\usepackage{fancyhdr} % 自定义页眉页脚
\usepackage{enumitem} % 列表项自定义
\usepackage{ifthen} % 条件判断(用于图片占位)
% --- 图片缺失占位宏 ---
\newcommand{\includegraphicsorplaceholder}[2][]{%
\IfFileExists{#2}{\includegraphics[#1]{#2}}{\fbox{\parbox[c][0.2\textheight][c]{0.9\textwidth}{\centering Missing image: #2}}}%
}
% --- 页眉页脚设置 ---
\pagestyle{fancy}
@@ -29,6 +35,8 @@
\fancyfoot[C]{\thepage} % 居中页脚:页码
\renewcommand{\headrulewidth}{0.4pt} % 页眉下方的横线粗细
\renewcommand{\footrulewidth}{0.4pt} % 页脚上方的横线粗细
% 解决 fancyhdr 提示的 \headheight 偏小问题
\setlength{\headheight}{15pt}
% --- 标题信息 ---
\title{\vspace{-2cm}\textbf{实验一:单周期 RISC-V CPU 设计与实现}} % 标题,垂直间距调整
@@ -155,7 +163,7 @@ when(io.jump_flag_id) {
\subsubsection{波形图}
\begin{figure}[htbp]
\centering
\includegraphics[width=0.9\textwidth]{b1.png}
\includegraphicsorplaceholder[width=0.9\textwidth]{b1.png}
\caption{取指模块 (\texttt{InstructionFetch}) 波形图}
\label{fig:if_waveform}
\end{figure}
@@ -191,7 +199,7 @@ io.wb_reg_write_source := MuxLookup(
\subsubsection{波形图}
\begin{figure}[htbp]
\centering
\includegraphics[width=0.9\textwidth]{b2.png}
\includegraphicsorplaceholder[width=0.9\textwidth]{b2.png}
\caption{译码模块 (\texttt{InstructionDecode}) 波形图}
\label{fig:id_waveform}
\end{figure}
@@ -205,7 +213,7 @@ io.wb_reg_write_source := MuxLookup(
\subsubsection{波形图}
\begin{figure}[htbp]
\centering
\includegraphics[width=0.9\textwidth]{b3.png}
\includegraphicsorplaceholder[width=0.9\textwidth]{b3.png}
\caption{执行模块 (\texttt{Execute}) 波形图}
\label{fig:ex_waveform}
\end{figure}
@@ -264,19 +272,20 @@ ex.io.aluop2_source := id.io.ex_aluop2_source
\subsubsection{波形图分析}
\begin{figure}[htbp]
\centering
\includegraphics[width=0.9\textwidth]{b2.png}
\caption{\texttt{L-Type} 指令 \texttt{lw x10, 32(x5)} 的译码波形图}
\includegraphicsorplaceholder[width=0.9\textwidth]{b2.png}
\caption{\texttt{L-Type} 指令 \texttt{lw x3, 0(x8)} 的译码波形图}
\label{fig:lw_decode_waveform}
\end{figure}
\ref{fig:lw_decode_waveform} 所示波形图展示了 \texttt{lw x10, 32(x5)} 指令(机器码 \texttt{0x02028503})的译码过程。在时钟上升沿之后:
图所示波形图展示了指令 lw x3, 0(x8)(机器码 0x00404183)的译码过程。在时钟上升沿之后:
\begin{itemize}
\item \texttt{id\_io\_instruction} 端口稳定为 \texttt{0x02028503}
\item \texttt{id\_io\_memory\_read\_enable}
\texttt{id\_io\_reg\_write\_enable} 信号被置为高电平 (1)
\item \texttt{id\_io\_wb\_reg\_write\_source} 信号变为 \texttt{01} (二进制),对应 \texttt{RegWriteSource.Memory}
\item \texttt{id\_io\_ex\_immediate} 的值为 \texttt{0x00000020},即十进制的 32。
\item \verb|id_io_instruction| 端口稳定为 \texttt{0x00404183},对应 I-type 的 Load 指令 \texttt{lw x3, 0(x8)}
\item \verb|id_io_memory_read_enable| 和 \verb|id_io_reg_write_enable| 信号被置为高电平1表示该指令需要从存储器读取数据并写回寄存器。
\item \verb|id_io_wb_reg_write_source| 信号值为 \texttt{01} (二进制),表示写回数据的来源是 Memory
\item \verb|id_io_ex_immediate| 的值为 \texttt{0x00000000},即偏移量 0
\end{itemize}
波形图直观地验证了译码模块对于 L-Type 指令的响应与 \texttt{expect} 语句的预期完全一致。
波形验证了译码模块对 I-type Load指令的控制信号输出与 \texttt{InstructionDecoderTest.scala} 中的 \texttt{expect} 语句一致,说明译码单元能够正确识别 Load 指令并产生相应控制信号。
\subsection{整体测试CPUTest (以 \texttt{FibonacciTest} 为例)}
@@ -307,23 +316,31 @@ c.io.mem_debug_read_data.expect(55.U) // 期望从地址 0x4 读出的数据为
\subsubsection{波形图分析}
\begin{figure}[htbp]
\centering
\includegraphics[width=0.9\textwidth]{b41.png}
\includegraphicsorplaceholder[width=0.9\textwidth]{b41.png}
\caption{Fibonacci 程序执行末期及结果写入内存的波形图}
\label{fig:fibonacci_waveform}
\end{figure}
\ref{fig:fibonacci_waveform} 展示了 \texttt{fibonacci} 程序执行的最后几个周期以及结果检查阶段。
基于 VCD 文件分析,斐波那契程序执行过程中的关键信号包括:
\begin{itemize}
\item \textbf{执行分析}: 在波形图的前半部分,可以看到 CPU 正在执行 \texttt{main} 函数中对 \texttt{fib(10)} 的调用,并最终将结果存储到内存地址 \texttt{0x4}。由于斐波那契数列的递归特性PC 会在函数调用和返回的过程中不断跳转。在程序即将结束时PC 会最终指向退出或停机指令。
\item \textbf{结果检查}: \texttt{main} 函数的核心是 \texttt{*(int *)(4) = fib(10);} 这条语句,它会在 \texttt{fib(10)} 的计算结果(即 55准备好后将其写入数据存储器的 \texttt{0x4} 地址。
在波形图的最后几个周期,我们会观察到以下关键信号变化:
\begin{itemize}
\item \texttt{mem\_io\_memory\_write\_enable} 信号短暂置高(为 \texttt{1}),表明数据存储器发生了写入操作
\item \texttt{mem\_io\_memory\_bundle\_address} 信号会显示为 \texttt{0x00000004},确认写入目标是内存地址 \texttt{0x4}
\item \texttt{mem\_io\_memory\_bundle\_write\_data[31:0]} 信号会显示为 \texttt{0x00000037}(十六进制的 55这是 \texttt{fib(10)} 的计算结果。
\item 在这之后,由于测试使用 \texttt{c.io.mem\_debug\_read\_address.poke(4.U)} 来读取内存,波形图上 \texttt{mem\_io\_debug\_read\_address} 会变为 \texttt{0x4},同时 \texttt{io\_mem\_debug\_read\_data}(或类似输出调试信号)会稳定显示出 \texttt{0x00000037}
\end{itemize}
\item \verb|cpu_io_instruction_address|程序计数器PC显示指令的执行流程
\item \verb|mem_io_bundle_write_enable|:内存写使能信号,用于标识数据写入操作;
\item \verb|mem_io_bundle_address|:内存访问地址;
\item \verb|mem_io_bundle_write_data|:写入内存的数据;
\item \verb|io_mem_debug_read_data|:调试接口读取的内存数据,用于结果验证
\end{itemize}
这些波形特征与 Chisel 测试中 \texttt{mem\_debug\_read\_data.expect(55.U)} 的断言完美吻合,证明 CPU 正确地执行了 \texttt{fibonacci} 程序并存储了预期结果。
所选测试程序为斐波那契数列求解程序,其功能是计算第 10 项的值(即 55并在程序结束时将结果写入数据存储器地址 \texttt{0x00000004}。在 \texttt{CPUTest.scala} 的测试中,系统通过监测访存信号或从调试接口读取该地址的值,验证处理器输出是否正确。
在程序执行的最后阶段,可以在波形中观察到以下现象:
\begin{enumerate}
\item \verb|mem_io_bundle_write_enable| 信号置高,表示 CPU 正在执行 \verb|sw| 指令;
\item \verb|mem_io_bundle_address| 显示为 \verb|0x00000004|,即目标内存地址为 4
\item \verb|mem_io_bundle_write_data| 显示为 \verb|0x00000037|(十进制 55\verb|fib(10)| 的计算结果;
\item 随后,调试接口 \verb|io_mem_debug_read_data| 读出并稳定为相同的值 \verb|0x00000037|。
\end{enumerate}
由此可知CPU 成功将计算结果 55 写入目标地址,测试检查结果正确,验证了数据通路及访存阶段的功能实现。
\section{遇到的问题与改进建议}
@@ -340,14 +357,9 @@ c.io.mem_debug_read_data.expect(55.U) // 期望从地址 0x4 读出的数据为
\item \textbf{建议}:实验文档中可以附加一个简单的调试案例,例如追踪一条 \texttt{add} 指令的数据流,展示如何从取指 PC 开始,逐步添加 `instruction`, `reg\_read\_data`, `alu\_result`, `reg\_write\_data` 等信号,并解释它们在波形图上的时序关系。
\end{itemize}
\item \textbf{问题:部分模块接口和控制信号的设计意图不够明确。}
例如,\texttt{ALUOp1Source}\texttt{ALUOp2Source} 这类控制信号的设计初衷,需要通过阅读多个模块的代码才能完全理解其作用。
\begin{itemize}
\item \textbf{建议}:在代码框架的注释中,对关键的 `object` 或 `Enum`(如 \texttt{ALUOp1Source}),增加注释来说明每个选项的用途和对应的指令场景。
\end{itemize}
\end{enumerate}
\section{实验结论}
通过本次实验,我成功设计并实现了一个功能基本完备的 RISC-V 单周期 CPU。在实现过程中我深入理解了数据通路与控制信号在指令执行过程中的协同作用并掌握了模块化的硬件设计思想。通过编写和分析单元测试与集成测试我学会了如何利用 \texttt{chiseltest}波形图对硬件设计进行验证和调试。本次实验极大地加深了我对计算机组成原理中理论知识的实践理解,为后续更复杂的处理器设计打下了坚实的基础。
通过本次实验,我成功设计并实现了一个功能基本完备的 RISC-V 单周期 CPU。在实现过程中我深入理解了数据通路与控制信号在指令执行过程中的协同作用并掌握了模块化的硬件设计思想。通过编写和分析单元测试与集成测试我学会了如何利用波形图对硬件设计进行验证和调试。本次实验极大地加深了我对计算机组成原理中理论知识的实践理解为后续更复杂的处理器设计打下了坚实的基础。
\end{document}

View File

@@ -134,6 +134,7 @@ class AXI4LiteSlave(addrWidth: Int, dataWidth: Int) extends Module {
val write_strobe = RegInit(VecInit(Seq.fill(Parameters.WordSize)(false.B)))
io.bundle.write_strobe := write_strobe
val read_issued = RegInit(false.B)
val ARREADY = RegInit(false.B)
io.channels.read_address_channel.ARREADY := ARREADY
val RVALID = RegInit(false.B)
@@ -153,7 +154,95 @@ class AXI4LiteSlave(addrWidth: Int, dataWidth: Int) extends Module {
val BRESP = WireInit(0.U(AXI4Lite.respWidth))
io.channels.write_response_channel.BRESP := BRESP
//lab4(BUS)
switch(state) {
is(AXI4LiteStates.Idle) {
// 默认状态:所有控制信号为低
ARREADY := false.B
RVALID := false.B
AWREADY := false.B
WREADY := false.B
BVALID := false.B
// 检测读地址通道的请求
when(io.channels.read_address_channel.ARVALID) {
read := false.B // 清除之前的read
state := AXI4LiteStates.ReadAddr
addr := io.channels.read_address_channel.ARADDR
ARREADY := true.B
}.elsewhen(io.channels.write_address_channel.AWVALID) {
write := false.B // 清除之前的write
// 检测写地址通道的请求
state := AXI4LiteStates.WriteAddr
addr := io.channels.write_address_channel.AWADDR
AWREADY := true.B
}.otherwise {
// 没有新请求时延迟清除read/write信号
read := false.B
write := false.B
}
}
is(AXI4LiteStates.ReadAddr) {
// 读地址握手完成发起读请求并进入ReadData
ARREADY := false.B
read := true.B
read_issued := false.B
state := AXI4LiteStates.ReadData
}
is(AXI4LiteStates.ReadData) {
// 保持read信号有效
read := true.B
when(!read_issued) {
// 第一个周期等待Memory准备数据
read_issued := true.B
}.otherwise {
// 第二个周期及之后:检查数据是否准备好
when(!RVALID && io.bundle.read_valid) {
// 数据准备好置RVALID
RVALID := true.B
}.elsewhen(RVALID && io.channels.read_data_channel.RREADY) {
// 握手完成返回Idleread会在Idle状态延迟清除
RVALID := false.B
read_issued := false.B
state := AXI4LiteStates.Idle
}
}
}
is(AXI4LiteStates.WriteAddr) {
// 写地址握手完成,等待写数据
AWREADY := false.B
when(io.channels.write_data_channel.WVALID) {
// 收到写数据
state := AXI4LiteStates.WriteData
for (i <- 0 until Parameters.WordSize) {
write_strobe(i) := io.channels.write_data_channel.WSTRB(i)
}
WREADY := true.B
write := true.B
}
}
is(AXI4LiteStates.WriteData) {
// 写数据握手完成,等待写入完成后发送响应
WREADY := false.B
write := false.B
state := AXI4LiteStates.WriteResp
BVALID := true.B
}
is(AXI4LiteStates.WriteResp) {
// 等待写响应握手
when(io.channels.write_response_channel.BREADY) {
// 写响应握手完成
BVALID := false.B
state := AXI4LiteStates.Idle
}
}
}
}
class AXI4LiteMaster(addrWidth: Int, dataWidth: Int) extends Module {
@@ -180,7 +269,7 @@ class AXI4LiteMaster(addrWidth: Int, dataWidth: Int) extends Module {
val RREADY = RegInit(false.B)
io.channels.read_data_channel.RREADY := RREADY
io.bundle.read_data := io.channels.read_data_channel.RDATA
io.bundle.read_data := read_data
val AWVALID = RegInit(false.B)
io.channels.write_address_channel.AWADDR := 0.U
io.channels.write_address_channel.AWVALID := AWVALID
@@ -192,5 +281,95 @@ class AXI4LiteMaster(addrWidth: Int, dataWidth: Int) extends Module {
val BREADY = RegInit(false.B)
io.channels.write_response_channel.BREADY := BREADY
//lab4(BUS)
// 清零valid信号如果不是刚刚被置1
when(read_valid) {
read_valid := false.B
}
when(write_valid) {
write_valid := false.B
}
switch(state) {
is(AXI4LiteStates.Idle) {
// 默认状态:所有控制信号为低
ARVALID := false.B
RREADY := false.B
AWVALID := false.B
WVALID := false.B
BREADY := false.B
// 检测读请求
when(io.bundle.read) {
state := AXI4LiteStates.ReadAddr
addr := io.bundle.address
ARVALID := true.B
}.elsewhen(io.bundle.write) {
// 检测写请求
state := AXI4LiteStates.WriteAddr
addr := io.bundle.address
write_data := io.bundle.write_data
write_strobe := io.bundle.write_strobe
AWVALID := true.B
}
}
is(AXI4LiteStates.ReadAddr) {
// 发送读地址,等待从机响应
ARVALID := true.B
io.channels.read_address_channel.ARADDR := addr
when(io.channels.read_address_channel.ARREADY) {
// 读地址握手完成
ARVALID := false.B
state := AXI4LiteStates.ReadData
RREADY := true.B
}
}
is(AXI4LiteStates.ReadData) {
// 等待读数据保持RREADY为高
RREADY := true.B
when(io.channels.read_data_channel.RVALID) {
// 读数据握手完成
read_data := io.channels.read_data_channel.RDATA
RREADY := false.B
read_valid := true.B
state := AXI4LiteStates.Idle
}
}
is(AXI4LiteStates.WriteAddr) {
// 发送写地址,等待从机响应
AWVALID := true.B
io.channels.write_address_channel.AWADDR := addr
when(io.channels.write_address_channel.AWREADY) {
// 写地址握手完成
AWVALID := false.B
state := AXI4LiteStates.WriteData
WVALID := true.B
}
}
is(AXI4LiteStates.WriteData) {
// 发送写数据保持WVALID为高
WVALID := true.B
when(io.channels.write_data_channel.WREADY) {
// 写数据握手完成
WVALID := false.B
state := AXI4LiteStates.WriteResp
BREADY := true.B
}
}
is(AXI4LiteStates.WriteResp) {
// 等待写响应保持BREADY为高
BREADY := true.B
when(io.channels.write_response_channel.BVALID) {
// 写响应握手完成
BREADY := false.B
write_valid := true.B
state := AXI4LiteStates.Idle
}
}
}
}