diff --git a/lab1/src/main/scala/riscv/core/CPU.scala b/lab1/src/main/scala/riscv/core/CPU.scala index 094229d..b2c7763 100644 --- a/lab1/src/main/scala/riscv/core/CPU.scala +++ b/lab1/src/main/scala/riscv/core/CPU.scala @@ -60,8 +60,6 @@ class CPU extends Module { - - // lab1(cpu) end diff --git a/lab1/src/main/scala/riscv/core/InstructionFetch.scala b/lab1/src/main/scala/riscv/core/InstructionFetch.scala index e6b5bfa..61bbdfb 100644 --- a/lab1/src/main/scala/riscv/core/InstructionFetch.scala +++ b/lab1/src/main/scala/riscv/core/InstructionFetch.scala @@ -44,7 +44,6 @@ class InstructionFetch extends Module { } - // la1(InstructionFetch) end diff --git a/lab1/实验报告/b41.png b/lab1/实验报告/b41.png index 745799c..86207e6 100644 Binary files a/lab1/实验报告/b41.png and b/lab1/实验报告/b41.png differ diff --git a/lab1/实验报告/report.aux b/lab1/实验报告/report.aux index b5c3fa8..d6f6f5c 100644 --- a/lab1/实验报告/report.aux +++ b/lab1/实验报告/report.aux @@ -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} diff --git a/lab1/实验报告/report.pdf b/lab1/实验报告/report.pdf index c1f1884..4e49779 100644 Binary files a/lab1/实验报告/report.pdf and b/lab1/实验报告/report.pdf differ diff --git a/lab1/实验报告/report.tex b/lab1/实验报告/report.tex index 6c2cdd4..5876e62 100644 --- a/lab1/实验报告/report.tex +++ b/lab1/实验报告/report.tex @@ -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} diff --git a/lab4/src/main/scala/bus/AXI4Lite.scala b/lab4/src/main/scala/bus/AXI4Lite.scala index b2f75fe..4386b8d 100644 --- a/lab4/src/main/scala/bus/AXI4Lite.scala +++ b/lab4/src/main/scala/bus/AXI4Lite.scala @@ -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) { + // 握手完成,返回Idle(read会在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 + } + } + } + }