<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>北航软院计组教程整理</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/</link><description>Recent content on 北航软院计组教程整理</description><generator>Hugo</generator><language>zh-Hans-CN</language><lastBuildDate>Sun, 26 Apr 2026 15:42:20 +0800</lastBuildDate><atom:link href="https://awesome-buaa-cs.github.io/fch-tutorial/index.xml" rel="self" type="application/rss+xml"/><item><title>My First Post</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/posts/my-first-post/</link><pubDate>Sun, 26 Apr 2026 15:42:20 +0800</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/posts/my-first-post/</guid><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This is &lt;strong&gt;bold&lt;/strong&gt; text, and this is &lt;em&gt;emphasized&lt;/em&gt; text.&lt;/p&gt;
&lt;p&gt;Visit the &lt;a href="https://gohugo.io"&gt;Hugo&lt;/a&gt; website!&lt;/p&gt;</description></item><item><title>4.1 实验目的</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/270/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/270/</guid><description>&lt;ol&gt;
&lt;li&gt;了解C语言程序的执行过程。&lt;/li&gt;
&lt;li&gt;理解汇编器原理，了解如何从MIPS汇编文件进行符号解析和指令汇编。&lt;/li&gt;
&lt;li&gt;了解不同MIPS分支指令，相对地址和绝对地址的区别，掌握不同符号的地址解析。&lt;/li&gt;
&lt;li&gt;理解链接器原理，掌握如何利用汇编器生成的可重定位目标文件，构造符号表，关联不同文件中的符号，并进行重定位，生成可运行的机器码。&lt;/li&gt;
&lt;li&gt;观察机器码如何在处理器上运行的。&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>4.1 实验目的</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/980/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/980/</guid><description>&lt;ol&gt;
&lt;li&gt;了解C语言程序的执行过程。&lt;/li&gt;
&lt;li&gt;理解汇编器原理，了解如何从MIPS汇编文件进行符号解析和指令汇编。&lt;/li&gt;
&lt;li&gt;了解不同MIPS分支指令，相对地址和绝对地址的区别，掌握不同符号的地址解析。&lt;/li&gt;
&lt;li&gt;理解链接器原理，掌握如何利用汇编器生成的可重定位目标文件，构造符号表，关联不同文件中的符号，并进行重定位，生成可运行的机器码。&lt;/li&gt;
&lt;li&gt;观察机器码如何在处理器上运行的。&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>4.2 程序的启动</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/271/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/271/</guid><description>&lt;p&gt;相信各位同学已经编写了不少高级语言的程序，我们可以理解自己编写代码的含义，但是计算机是如何理解并准确无误地执行我们的代码的。这一过程并不是一个启动按钮，或是一行指令。&lt;/p&gt;
&lt;p&gt;实际上，程序的启动是一个相当复杂的过程，对于C语言而言，涉及了四个相对独立的功能模块，分别是：编译器（Compiler），汇编器（Assembler），链接器（Linker），加载器（Loader）。他们按照一定的次序工作，上一层的输出产物成为下一层的输入，逐步将程序转换成与实际计算机系统硬件相关的，计算机可以理解执行的程序（C.A.L.L.过程）。如下图所示：&lt;/p&gt;
&lt;img src="../images/30489ll1669605086.PNG" style="zoom:70%" align=center&gt;
&lt;ul&gt;
&lt;li&gt;为了确定文件类型UNIX使用文件的后缀，&lt;code&gt;x.c&lt;/code&gt;表示C源文件，&lt;code&gt;x.s&lt;/code&gt;表示汇编文件，&lt;code&gt;x.o&lt;/code&gt;表示目标文件，&lt;code&gt;x.a&lt;/code&gt;表示静态链接库，&lt;code&gt;x.so&lt;/code&gt;表示动态链接库。默认情况下，&lt;code&gt;a.out&lt;/code&gt;表示可执行文件。&lt;/li&gt;
&lt;li&gt;MS-DOS使用&lt;code&gt;.C, .ASM, .OBJ, .LIB, .DLL, .EXE&lt;/code&gt;来完成相同功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="421-代码编译"&gt;4.2.1 代码编译&lt;/h3&gt;
&lt;p&gt;编译器将C程序转换成一种机器可以理解的符号形式的&lt;strong&gt;汇编语言&lt;/strong&gt;程序，它能够被进一步翻译成二进制机器语言。&lt;/p&gt;
&lt;h3 id="422-代码汇编"&gt;4.2.2 代码汇编&lt;/h3&gt;
&lt;p&gt;由编译器生成的汇编程序中，存在着简化程序转换和编程的一些实际硬件不支持的指令，这类指令称为&lt;strong&gt;伪指令(pseudoinsruction)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;例如，MIPS硬件确保寄存器&lt;code&gt;$zero&lt;/code&gt;保持0。即一旦使用该寄存器，它都能提供0，而且程序员不能修改寄存器&lt;code&gt;$zero&lt;/code&gt;的值。寄存器&lt;code&gt;$zero&lt;/code&gt;用于生成汇编语言指令&lt;code&gt;move&lt;/code&gt;。&lt;code&gt;move&lt;/code&gt;的功能是将一个寄存器中的内容复制到另一个中。因此即使MIPS体系结构不存在这条指令，MIPS汇编器依然可以识别它。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$t1&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 寄存器$t0得到寄存器$t1的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;汇编器将这条汇编语言指令转换成等价的机器语言指令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$zero&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$t1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;总的来说，伪指令使得MIPS拥有比硬件所实现的更为丰富的汇编语言指令集。唯一的代价是保留了&lt;code&gt;$at&lt;/code&gt;寄存器。&lt;strong&gt;本次实验中也存在着将伪指令扩展成通用指令的任务。&lt;/strong&gt;
汇编器的主要任务是汇编成机器代码。汇编器将汇编语言程序转换成&lt;strong&gt;目标文件(object file)&lt;/strong&gt;，它包括机器语言指令，数据和指令正确放入内存所需要的信息。
为了产生汇编语言程序每条指令对应的二进制表示，汇编器必须处理所有标号对应的地址，汇编器将分支和数据传输指令中用到的标号都放入一个**符号表(Symbol Table)**中。这个表由标号和地址组成。
UNIX系统中的目标文件通常包括以下6个不同部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;目标文件头，描述目标文件其他部分的大小和位置&lt;/li&gt;
&lt;li&gt;代码段，包含机器语言代码&lt;/li&gt;
&lt;li&gt;静态数据段，包含在程序生命周期内分配的数据&lt;/li&gt;
&lt;li&gt;重定位信息，标记了一些在程序加载进内存时依赖于绝对地址的指令和数据&lt;/li&gt;
&lt;li&gt;符号表，包含未定义的剩余标记，如外部引用&lt;/li&gt;
&lt;li&gt;调试信息，包括了一份说明目标模块如何编译的简明描述&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="423-代码链接"&gt;4.2.3 代码链接&lt;/h3&gt;
&lt;p&gt;到目前为止我们描述的所有内容表明，对源程序的任意一行代码的修改都需要重新编译和汇编整个程序，全部的编译和汇编效率是低下的，尤其对于标准库而言。因而出现了另一种方法，即单独编译和汇编每个过程，使得某一行代码的修改只需要编译和汇编一个过程，这种方法需要一个新的系统程序，称为&lt;strong&gt;链接器(Linker)&lt;/strong&gt;。它把所有独立汇编的机器语言程序&lt;em&gt;拼接&lt;/em&gt;在一起。&lt;/p&gt;
&lt;p&gt;链接器的工作分为三个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将代码和数据模块象征性地放入内存&lt;/li&gt;
&lt;li&gt;决定数据和指令标签的地址&lt;/li&gt;
&lt;li&gt;修补内部和外部引用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;链接器使用每个目标模块中的重定位信息和符号表，来解析所有未定义标签，这种引用发生在分支指令，跳转指令和数据寻址处。它的工作非常像一个编辑器，寻找所有旧地址并用新地址加以代替。
如果所有外部引用都解析完成，链接器接着要确定每个模块将要占用的内存位置。因为文件是单独汇编的，所以汇编器不可能知道该模块指令和数据相对于其他模块而言的位置，因此也就无从确定他们的内存位置。当链接器将一个模块放到内存中的时候，所有的&lt;strong&gt;绝对引用&lt;/strong&gt;（与寄存器无关的内存地址），必须&lt;strong&gt;重定位&lt;/strong&gt;来反映它们的真实地址。
链接器将产生一个&lt;strong&gt;可执行文件(Executable file)&lt;/strong&gt;，它可以在一台计算机上运行，通常，这个文件与目标文件具有相同的格式，但是它不包含未解决的引用。&lt;/p&gt;
&lt;h3 id="424-代码加载"&gt;4.2.4 代码加载&lt;/h3&gt;
&lt;p&gt;现在可执行文件已经存在于磁盘中，操作系统就可以将其读入内存并启动执行该程序，在UNIX系统中，**加载器(Loader)**按照以下步骤工作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读取可执行文件头来确定代码段和数据段的大小&lt;/li&gt;
&lt;li&gt;为正文和数据创建一个足够大的地址空间&lt;/li&gt;
&lt;li&gt;将可执行文件中的指令和数据复制到内存中&lt;/li&gt;
&lt;li&gt;把主程序的参数复制到栈顶&lt;/li&gt;
&lt;li&gt;初始化机器寄存器，将栈指针指向第一个空位置&lt;/li&gt;
&lt;li&gt;跳转到启动例程，它将参数复制到参数寄存器并且调用程序的main函数，当main函数返回时，启动例程通过系统调用exit终止程序&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来，就让我们一起构造我们自己的汇编器和链接器！&lt;/p&gt;</description></item><item><title>4.2 程序的启动</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/981/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/981/</guid><description>&lt;p&gt;相信各位同学已经编写了不少高级语言的程序，我们可以理解自己编写代码的含义，但是计算机是如何理解并准确无误地执行我们的代码的。这一过程并不是一个启动按钮，或是一行指令。&lt;/p&gt;
&lt;p&gt;实际上，程序的启动是一个相当复杂的过程，对于C语言而言，涉及了四个相对独立的功能模块，分别是：编译器（Compiler），汇编器（Assembler），链接器（Linker），加载器（Loader）。他们按照一定的次序工作，上一层的输出产物成为下一层的输入，逐步将程序转换成与实际计算机系统硬件相关的，计算机可以理解执行的程序（C.A.L.L.过程）。如下图所示：&lt;/p&gt;
&lt;img src="../images/30489ll1669605086.PNG" style="zoom:70%" align=center&gt;
&lt;ul&gt;
&lt;li&gt;为了确定文件类型UNIX使用文件的后缀，&lt;code&gt;x.c&lt;/code&gt;表示C源文件，&lt;code&gt;x.s&lt;/code&gt;表示汇编文件，&lt;code&gt;x.o&lt;/code&gt;表示目标文件，&lt;code&gt;x.a&lt;/code&gt;表示静态链接库，&lt;code&gt;x.so&lt;/code&gt;表示动态链接库。默认情况下，&lt;code&gt;a.out&lt;/code&gt;表示可执行文件。&lt;/li&gt;
&lt;li&gt;MS-DOS使用&lt;code&gt;.C, .ASM, .OBJ, .LIB, .DLL, .EXE&lt;/code&gt;来完成相同功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="421-代码编译"&gt;4.2.1 代码编译&lt;/h3&gt;
&lt;p&gt;编译器将C程序转换成一种机器可以理解的符号形式的&lt;strong&gt;汇编语言&lt;/strong&gt;程序，它能够被进一步翻译成二进制机器语言。&lt;/p&gt;
&lt;h3 id="422-代码汇编"&gt;4.2.2 代码汇编&lt;/h3&gt;
&lt;p&gt;由编译器生成的汇编程序中，存在着简化程序转换和编程的一些实际硬件不支持的指令，这类指令称为&lt;strong&gt;伪指令(pseudoinsruction)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;例如，MIPS硬件确保寄存器&lt;code&gt;$zero&lt;/code&gt;保持0。即一旦使用该寄存器，它都能提供0，而且程序员不能修改寄存器&lt;code&gt;$zero&lt;/code&gt;的值。寄存器&lt;code&gt;$zero&lt;/code&gt;用于生成汇编语言指令&lt;code&gt;move&lt;/code&gt;。&lt;code&gt;move&lt;/code&gt;的功能是将一个寄存器中的内容复制到另一个中。因此即使MIPS体系结构不存在这条指令，MIPS汇编器依然可以识别它。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$t1&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 寄存器$t0得到寄存器$t1的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;汇编器将这条汇编语言指令转换成等价的机器语言指令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$zero&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$t1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;总的来说，伪指令使得MIPS拥有比硬件所实现的更为丰富的汇编语言指令集。唯一的代价是保留了&lt;code&gt;$at&lt;/code&gt;寄存器。&lt;strong&gt;本次实验中也存在着将伪指令扩展成通用指令的任务。&lt;/strong&gt;
汇编器的主要任务是汇编成机器代码。汇编器将汇编语言程序转换成&lt;strong&gt;目标文件(object file)&lt;/strong&gt;，它包括机器语言指令，数据和指令正确放入内存所需要的信息。
为了产生汇编语言程序每条指令对应的二进制表示，汇编器必须处理所有标号对应的地址，汇编器将分支和数据传输指令中用到的标号都放入一个**符号表(Symbol Table)**中。这个表由标号和地址组成。
UNIX系统中的目标文件通常包括以下6个不同部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;目标文件头，描述目标文件其他部分的大小和位置&lt;/li&gt;
&lt;li&gt;代码段，包含机器语言代码&lt;/li&gt;
&lt;li&gt;静态数据段，包含在程序生命周期内分配的数据&lt;/li&gt;
&lt;li&gt;重定位信息，标记了一些在程序加载进内存时依赖于绝对地址的指令和数据&lt;/li&gt;
&lt;li&gt;符号表，包含未定义的剩余标记，如外部引用&lt;/li&gt;
&lt;li&gt;调试信息，包括了一份说明目标模块如何编译的简明描述&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="423-代码链接"&gt;4.2.3 代码链接&lt;/h3&gt;
&lt;p&gt;到目前为止我们描述的所有内容表明，对源程序的任意一行代码的修改都需要重新编译和汇编整个程序，全部的编译和汇编效率是低下的，尤其对于标准库而言。因而出现了另一种方法，即单独编译和汇编每个过程，使得某一行代码的修改只需要编译和汇编一个过程，这种方法需要一个新的系统程序，称为&lt;strong&gt;链接器(Linker)&lt;/strong&gt;。它把所有独立汇编的机器语言程序&lt;em&gt;拼接&lt;/em&gt;在一起。&lt;/p&gt;
&lt;p&gt;链接器的工作分为三个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将代码和数据模块象征性地放入内存&lt;/li&gt;
&lt;li&gt;决定数据和指令标签的地址&lt;/li&gt;
&lt;li&gt;修补内部和外部引用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;链接器使用每个目标模块中的重定位信息和符号表，来解析所有未定义标签，这种引用发生在分支指令，跳转指令和数据寻址处。它的工作非常像一个编辑器，寻找所有旧地址并用新地址加以代替。
如果所有外部引用都解析完成，链接器接着要确定每个模块将要占用的内存位置。因为文件是单独汇编的，所以汇编器不可能知道该模块指令和数据相对于其他模块而言的位置，因此也就无从确定他们的内存位置。当链接器将一个模块放到内存中的时候，所有的&lt;strong&gt;绝对引用&lt;/strong&gt;（与寄存器无关的内存地址），必须&lt;strong&gt;重定位&lt;/strong&gt;来反映它们的真实地址。
链接器将产生一个&lt;strong&gt;可执行文件(Executable file)&lt;/strong&gt;，它可以在一台计算机上运行，通常，这个文件与目标文件具有相同的格式，但是它不包含未解决的引用。&lt;/p&gt;
&lt;h3 id="424-代码加载"&gt;4.2.4 代码加载&lt;/h3&gt;
&lt;p&gt;现在可执行文件已经存在于磁盘中，操作系统就可以将其读入内存并启动执行该程序，在UNIX系统中，**加载器(Loader)**按照以下步骤工作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读取可执行文件头来确定代码段和数据段的大小&lt;/li&gt;
&lt;li&gt;为正文和数据创建一个足够大的地址空间&lt;/li&gt;
&lt;li&gt;将可执行文件中的指令和数据复制到内存中&lt;/li&gt;
&lt;li&gt;把主程序的参数复制到栈顶&lt;/li&gt;
&lt;li&gt;初始化机器寄存器，将栈指针指向第一个空位置&lt;/li&gt;
&lt;li&gt;跳转到启动例程，它将参数复制到参数寄存器并且调用程序的main函数，当main函数返回时，启动例程通过系统调用exit终止程序&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来，就让我们一起构造我们自己的汇编器和链接器！&lt;/p&gt;</description></item><item><title>4.3 汇编器</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/272/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/272/</guid><description>&lt;h3 id="431-汇编器原理详解"&gt;4.3.1 汇编器原理详解&lt;/h3&gt;
&lt;p&gt;正如上文所述，汇编器将汇编语言文件翻译成二进制机器指令和二进制数据组成的文件，我们将在下文阐述MIPS汇编器的实现细节。
首先我们先来看看汇编器在处理过程中可能面临的一些情况：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;简单情况：
&lt;ul&gt;
&lt;li&gt;计算和逻辑指令，例如&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; addu rd, rs, rt
 mult rs, rt
 lw rt, offset(rs)
&lt;/code&gt;&lt;/pre&gt;等；
&lt;ul&gt;
&lt;li&gt;为将其汇编成二进制指令所需要的所有信息都已经包含在了指令中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;分支指令(Branch)：
&lt;ul&gt;
&lt;li&gt;分支指令中的&lt;code&gt;imm&lt;/code&gt;字段代表的是相对当前指令地址的偏移量，即需要的是相对地址；&lt;/li&gt;
&lt;li&gt;一旦将所有的伪指令解析成实际的机器代码以后，由于MIPS是定长指令，因此通过简单的计算我们便可以得到实际的地址偏移量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;前向引用：汇编语言允许标签在定义之前就被使用，如下图所示：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$zero&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$zero&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;Label&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Label:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;汇编器在看到指令&lt;code&gt;beq&lt;/code&gt;时，它不知道标签Label在哪里，因此也就无从得知相对地址偏移量了。&lt;/p&gt;
&lt;p&gt;为解决这个问题，我们首先引入一个概念——遍(&lt;strong&gt;Pass&lt;/strong&gt;)。它指的是对源程序（包括源程序的中间形式）从头到尾扫描一次，并做有关的加工处理，生成新的源程序中间形式或目标程序，通常称为遍。&lt;/p&gt;
&lt;p&gt;汇编器通常采用两遍的方式来处理可能出现的前向引用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;第一遍，汇编器将汇编文件的每一行读入，如果一行以标签作为开始，汇编器在他的符号表中记录标签的名字以及在文件中的位置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第二遍，汇编器使用整个文件的符号表中的信息，在这一遍产生机器代码，若依然有未决的引用，将由链接器来进行解析：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;跳转指令：例如&lt;code&gt;j, jal&lt;/code&gt;指令，这类跳转指令需要跳转的绝对地址，汇编器对于单一文件的操作，不可能得到最终的绝对地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据引用：例如&lt;code&gt;la&lt;/code&gt;指令，&lt;code&gt;la&lt;/code&gt;指令将由汇编器处理为&lt;code&gt;lui&lt;/code&gt;和&lt;code&gt;ori&lt;/code&gt;指令，同样需要32位的绝对地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;外部引用：&lt;code&gt;jal&lt;/code&gt;指令可能跳转到外部文件的函数（就如C语言引用库函数），汇编器处理单一文件无法获取外部引用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以看到，我们对于需要绝对地址的指令以及外部引用都是无法解析的，因此汇编器将创建两张表。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;符号定义表&lt;/strong&gt;(&lt;strong&gt;Symbol Table&lt;/strong&gt;)：每个文件都有一个符号定义表，用来记录该文件中定义的标签，这些标签可能被其他文件引用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文本段标签：
1. 跳转标签，如循环时定义的 For/Loop/End 等标签；
2. 函数定义，如 main/add 等自行定义的函数；&lt;/li&gt;
&lt;li&gt;数据段标签：出现在文件&lt;code&gt;.data&lt;/code&gt;段的数据标签。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重定位表&lt;/strong&gt;(&lt;strong&gt;Relocation Table&lt;/strong&gt;)：该文件中暂时无法确定的，需要在之后的过程中得到地址的标签：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;j, jal&lt;/code&gt;等指令的&lt;strong&gt;跳转标签&lt;/strong&gt;，一般都是在&lt;strong&gt;文本段中&lt;/strong&gt;定义的，无论是文件内定义的还是文件以外定义的；&lt;/li&gt;
&lt;li&gt;任何可能的&lt;strong&gt;数据标签&lt;/strong&gt;，例如所有被&lt;code&gt;la&lt;/code&gt;指令引用的数据标签。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="432-汇编器具体实现"&gt;4.3.2 汇编器具体实现&lt;/h3&gt;
&lt;h4 id="汇编器实现概述"&gt;汇编器实现概述&lt;/h4&gt;
&lt;p&gt;本次实验，我们的汇编器将实现一个MIPS指令的子集。同时我们的汇编器是一个如上文描述的**“两遍”**汇编器，实现汇编.data和.text段。它将按照以下流程工作：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一遍&lt;/strong&gt;：读取输入的.s文件&lt;/p&gt;
&lt;p&gt;举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;num: &lt;span style="color:#a6e22e"&gt;.space&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;num2: &lt;span style="color:#a6e22e"&gt;.space&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;jr&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;main:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;la&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v1&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;jal&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;j&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;end:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;剔除文件注释（在.s文件中，注释为#开头的单行注释）；&lt;/li&gt;
&lt;li&gt;扩展伪指令，如&lt;code&gt;li&lt;/code&gt;, &lt;code&gt;la&lt;/code&gt;等；&lt;/li&gt;
&lt;li&gt;记录文件符号，构建相应的符号定义表；
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;注意&lt;/strong&gt;：在我们的处理中，为了区分符号是来自&lt;code&gt;.data&lt;/code&gt;段还是来自&lt;code&gt;.text&lt;/code&gt;段，我们为来自&lt;code&gt;.data&lt;/code&gt;段中的符号，在符号名最开始追加一个&lt;code&gt;%&lt;/code&gt;用于在符号定义表中区分。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;标签（是否重复定义）和伪指令（是否合法）将被检查确认；&lt;/li&gt;
&lt;li&gt;输出：中间文件（.int），对于&lt;code&gt;.data&lt;/code&gt;段，只需要输出&lt;code&gt;.data&lt;/code&gt;段所占据的字节数即可，按照如下格式：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jr&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lui&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$at&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;num@Hi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ori&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$at&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;num@Lo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addiu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addiu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jal&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;j&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第二遍&lt;/strong&gt;：读取.int中间文件&lt;/p&gt;</description></item><item><title>4.3 汇编器</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/982/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/982/</guid><description>&lt;h3 id="431-汇编器原理详解"&gt;4.3.1 汇编器原理详解&lt;/h3&gt;
&lt;p&gt;正如上文所述，汇编器将汇编语言文件翻译成二进制机器指令和二进制数据组成的文件，我们将在下文阐述MIPS汇编器的实现细节。
首先我们先来看看汇编器在处理过程中可能面临的一些情况：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;简单情况：
&lt;ul&gt;
&lt;li&gt;计算和逻辑指令，例如&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; addu rd, rs, rt
 mult rs, rt
 lw rt, offset(rs)
&lt;/code&gt;&lt;/pre&gt;等；
&lt;ul&gt;
&lt;li&gt;为将其汇编成二进制指令所需要的所有信息都已经包含在了指令中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;分支指令(Branch)：
&lt;ul&gt;
&lt;li&gt;分支指令中的&lt;code&gt;imm&lt;/code&gt;字段代表的是相对当前指令地址的偏移量，即需要的是相对地址；&lt;/li&gt;
&lt;li&gt;一旦将所有的伪指令解析成实际的机器代码以后，由于MIPS是定长指令，因此通过简单的计算我们便可以得到实际的地址偏移量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;前向引用：汇编语言允许标签在定义之前就被使用，如下图所示：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$zero&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$zero&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;Label&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Label:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;汇编器在看到指令&lt;code&gt;beq&lt;/code&gt;时，它不知道标签Label在哪里，因此也就无从得知相对地址偏移量了。&lt;/p&gt;
&lt;p&gt;为解决这个问题，我们首先引入一个概念——遍(&lt;strong&gt;Pass&lt;/strong&gt;)。它指的是对源程序（包括源程序的中间形式）从头到尾扫描一次，并做有关的加工处理，生成新的源程序中间形式或目标程序，通常称为遍。&lt;/p&gt;
&lt;p&gt;汇编器通常采用两遍的方式来处理可能出现的前向引用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;第一遍，汇编器将汇编文件的每一行读入，如果一行以标签作为开始，汇编器在他的符号表中记录标签的名字以及在文件中的位置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第二遍，汇编器使用整个文件的符号表中的信息，在这一遍产生机器代码，若依然有未决的引用，将由链接器来进行解析：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;跳转指令：例如&lt;code&gt;j, jal&lt;/code&gt;指令，这类跳转指令需要跳转的绝对地址，汇编器对于单一文件的操作，不可能得到最终的绝对地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据引用：例如&lt;code&gt;la&lt;/code&gt;指令，&lt;code&gt;la&lt;/code&gt;指令将由汇编器处理为&lt;code&gt;lui&lt;/code&gt;和&lt;code&gt;ori&lt;/code&gt;指令，同样需要32位的绝对地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;外部引用：&lt;code&gt;jal&lt;/code&gt;指令可能跳转到外部文件的函数（就如C语言引用库函数），汇编器处理单一文件无法获取外部引用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以看到，我们对于需要绝对地址的指令以及外部引用都是无法解析的，因此汇编器将创建两张表。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;符号定义表&lt;/strong&gt;(&lt;strong&gt;Symbol Table&lt;/strong&gt;)：每个文件都有一个符号定义表，用来记录该文件中定义的标签，这些标签可能被其他文件引用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文本段标签：
1. 跳转标签，如循环时定义的 For/Loop/End 等标签；
2. 函数定义，如 main/add 等自行定义的函数；&lt;/li&gt;
&lt;li&gt;数据段标签：出现在文件&lt;code&gt;.data&lt;/code&gt;段的数据标签。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重定位表&lt;/strong&gt;(&lt;strong&gt;Relocation Table&lt;/strong&gt;)：该文件中暂时无法确定的，需要在之后的过程中得到地址的标签：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;j, jal&lt;/code&gt;等指令的&lt;strong&gt;跳转标签&lt;/strong&gt;，一般都是在&lt;strong&gt;文本段中&lt;/strong&gt;定义的，无论是文件内定义的还是文件以外定义的；&lt;/li&gt;
&lt;li&gt;任何可能的&lt;strong&gt;数据标签&lt;/strong&gt;，例如所有被&lt;code&gt;la&lt;/code&gt;指令引用的数据标签。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="432-汇编器具体实现"&gt;4.3.2 汇编器具体实现&lt;/h3&gt;
&lt;h4 id="汇编器实现概述"&gt;汇编器实现概述&lt;/h4&gt;
&lt;p&gt;本次实验，我们的汇编器将实现一个MIPS指令的子集。同时我们的汇编器是一个如上文描述的**“两遍”**汇编器，实现汇编.data和.text段。它将按照以下流程工作：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一遍&lt;/strong&gt;：读取输入的.s文件&lt;/p&gt;
&lt;p&gt;举例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;num: &lt;span style="color:#a6e22e"&gt;.space&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;num2: &lt;span style="color:#a6e22e"&gt;.space&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;jr&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;main:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;la&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v1&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;jal&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;j&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;end:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;剔除文件注释（在.s文件中，注释为#开头的单行注释）；&lt;/li&gt;
&lt;li&gt;扩展伪指令，如&lt;code&gt;li&lt;/code&gt;, &lt;code&gt;la&lt;/code&gt;等；&lt;/li&gt;
&lt;li&gt;记录文件符号，构建相应的符号定义表；
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;注意&lt;/strong&gt;：在我们的处理中，为了区分符号是来自&lt;code&gt;.data&lt;/code&gt;段还是来自&lt;code&gt;.text&lt;/code&gt;段，我们为来自&lt;code&gt;.data&lt;/code&gt;段中的符号，在符号名最开始追加一个&lt;code&gt;%&lt;/code&gt;用于在符号定义表中区分。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;标签（是否重复定义）和伪指令（是否合法）将被检查确认；&lt;/li&gt;
&lt;li&gt;输出：中间文件（.int），对于&lt;code&gt;.data&lt;/code&gt;段，只需要输出&lt;code&gt;.data&lt;/code&gt;段所占据的字节数即可，按照如下格式：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s5&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jr&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lui&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$at&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;num@Hi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ori&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$at&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;num@Lo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addiu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addiu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt; -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jal&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;addu&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;j&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第二遍&lt;/strong&gt;：读取.int中间文件&lt;/p&gt;</description></item><item><title>4.4 链接器</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/273/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/273/</guid><description>&lt;h3 id="441-链接器原理详解"&gt;4.4.1 链接器原理详解&lt;/h3&gt;
&lt;p&gt;链接器读取我们汇编器输出的数个.o文件，利用目标文件中的信息，进行符号解析，最终输出可执行的机器代码，例如（&lt;code&gt;a.out&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/6a0ed56c4cd8f91d72adc7629d40f38c.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;链接器能够得到每个文件的text和data段的大小以及它们的顺序。利用这些，链接器便可以计算每个符号的绝对地址。&lt;/p&gt;
&lt;p&gt;为了解析符号，链接器首先搜索每个文件的符号表（即每个文件定义的符号），如果没有找到，将继续在库文件中搜索(例如&lt;code&gt;printf&lt;/code&gt;)。一旦获取到符号的定义位置，链接器就会填入实际的地址，完善机器代码。最终链接器输出的可执行文件包括&lt;code&gt;.text&lt;/code&gt;和&lt;code&gt;.data&lt;/code&gt;段（加上ELF文件头）。&lt;/p&gt;
&lt;p&gt;对于我们的链接器而言，有四类地址：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PC相对地址(&lt;code&gt;beq, bne&lt;/code&gt;)：不需要重定位，在汇编器汇编阶段已经确定了地址；&lt;/li&gt;
&lt;li&gt;绝对地址(&lt;code&gt;j, jal&lt;/code&gt;)：需要重定位，对应文本段中的跳转标签；&lt;/li&gt;
&lt;li&gt;外部引用(&lt;code&gt;jal&lt;/code&gt;)：需要重定位，对应文本段中的函数标签；&lt;/li&gt;
&lt;li&gt;数据引用(&lt;code&gt;la&lt;/code&gt;)：在汇编器中我们将其拆分为&lt;code&gt;lui-ori&lt;/code&gt;指令对，需要重定位，对应数据段标签。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="442-链接器具体实现"&gt;4.4.2 链接器具体实现&lt;/h3&gt;
&lt;h4 id="链接器实现概述"&gt;链接器实现概述&lt;/h4&gt;
&lt;p&gt;我们在汇编器中，解析了&lt;code&gt;.data&lt;/code&gt;和&lt;code&gt;.text&lt;/code&gt;段，因此我们在这里也将实现一个简化过的链接器，它将把一个或多个.o文件的&lt;code&gt;.data&lt;/code&gt;和&lt;code&gt;.text&lt;/code&gt;合并在一起来创建可执行的机器代码，但是我们不会为其添加ELF文件头，因此你可以认为我们的输出是可执行文件去掉ELF文件头以后的二进制bin文件。
具体的链接步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建一个空的&lt;strong&gt;全局&lt;/strong&gt;符号定义表，这里将存储所有文件中符号（定义位置）的绝对地址，因此每个符号&lt;strong&gt;至多出现一次&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;对于每个目标文件都创建一个&lt;strong&gt;独立的&lt;/strong&gt;重定位表，将包含每个需要重定位符号的相对地址；&lt;/li&gt;
&lt;li&gt;打开每个目标文件，分别读取它的&lt;code&gt;.data&lt;/code&gt;, &lt;code&gt;.text&lt;/code&gt;, &lt;code&gt;.symbol&lt;/code&gt;, &lt;code&gt;.relocation&lt;/code&gt;段：
&lt;ul&gt;
&lt;li&gt;如果是&lt;code&gt;.data&lt;/code&gt;段，读取该文件&lt;code&gt;.data&lt;/code&gt;段的大小，用于计算上述提到的绝对地址；&lt;/li&gt;
&lt;li&gt;如果是&lt;code&gt;.text&lt;/code&gt;段，计算指令数目，得到该文件的指令将会占用多少字节（MIPS 的每条指令固定为 4 字节）；&lt;/li&gt;
&lt;li&gt;如果是&lt;code&gt;.symbol&lt;/code&gt;段，将其读入，将相对地址转换为绝对地址（&lt;strong&gt;怎么做？&lt;/strong&gt;），并合并进第 1 步创建的全局符号表；&lt;/li&gt;
&lt;li&gt;如果是&lt;code&gt;.relocation&lt;/code&gt;段，将其读入进该文件的重定位表，保留其相对地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;打开输出文件；&lt;/li&gt;
&lt;li&gt;再次打开每个目标文件，读取&lt;code&gt;.text&lt;/code&gt;段，通过查找重定位表判断每条指令是否需要重定位，如果需要，使用符号表查找符号的绝对地址，并填入指令的相应字段，最终输出重定向后的指令即可。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="链接器实现"&gt;链接器实现&lt;/h4&gt;
&lt;p&gt;链接器整体调用关系如下：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/f815e944dea614d90544031b8a9a5cad.png" alt="linker"&gt;&lt;/p&gt;
&lt;p&gt;我们在汇编器的重定位表中引入新的结构体&lt;code&gt;RelocData&lt;/code&gt;(定义在&lt;code&gt;linker_utils.h&lt;/code&gt;)，主要是在重定位表中加入：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字段&lt;code&gt;text_size&lt;/code&gt;用于记录该文件的&lt;code&gt;.text&lt;/code&gt;段需要占据的字节数；&lt;/li&gt;
&lt;li&gt;字段&lt;code&gt;data_size&lt;/code&gt;用于记录该文件的&lt;code&gt;.data&lt;/code&gt;段需要占据的字节数；&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SymbolTable &lt;span style="color:#f92672"&gt;*&lt;/span&gt;table; &lt;span style="color:#75715e"&gt;//重定位表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; text_size; &lt;span style="color:#75715e"&gt;//相应文件.text段大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; data_size; &lt;span style="color:#75715e"&gt;//相应文件.data段大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} RelocData;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="测试样例"&gt;测试样例&lt;/h4&gt;
&lt;p&gt;为了便于理解，提供以下样例以供参考：&lt;/p&gt;
&lt;p&gt;有以下两个.s文件需要进行处理：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.s&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;num: &lt;span style="color:#a6e22e"&gt;.space&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;main:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;la&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v1&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;jal&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;j&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;end:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;add.s&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>4.4 链接器</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/983/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/983/</guid><description>&lt;h3 id="441-链接器原理详解"&gt;4.4.1 链接器原理详解&lt;/h3&gt;
&lt;p&gt;链接器读取我们汇编器输出的数个.o文件，利用目标文件中的信息，进行符号解析，最终输出可执行的机器代码，例如（&lt;code&gt;a.out&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/6a0ed56c4cd8f91d72adc7629d40f38c.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;链接器能够得到每个文件的text和data段的大小以及它们的顺序。利用这些，链接器便可以计算每个符号的绝对地址。&lt;/p&gt;
&lt;p&gt;为了解析符号，链接器首先搜索每个文件的符号表（即每个文件定义的符号），如果没有找到，将继续在库文件中搜索(例如&lt;code&gt;printf&lt;/code&gt;)。一旦获取到符号的定义位置，链接器就会填入实际的地址，完善机器代码。最终链接器输出的可执行文件包括&lt;code&gt;.text&lt;/code&gt;和&lt;code&gt;.data&lt;/code&gt;段（加上ELF文件头）。&lt;/p&gt;
&lt;p&gt;对于我们的链接器而言，有四类地址：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PC相对地址(&lt;code&gt;beq, bne&lt;/code&gt;)：不需要重定位，在汇编器汇编阶段已经确定了地址；&lt;/li&gt;
&lt;li&gt;绝对地址(&lt;code&gt;j, jal&lt;/code&gt;)：需要重定位，对应文本段中的跳转标签；&lt;/li&gt;
&lt;li&gt;外部引用(&lt;code&gt;jal&lt;/code&gt;)：需要重定位，对应文本段中的函数标签；&lt;/li&gt;
&lt;li&gt;数据引用(&lt;code&gt;la&lt;/code&gt;)：在汇编器中我们将其拆分为&lt;code&gt;lui-ori&lt;/code&gt;指令对，需要重定位，对应数据段标签。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="442-链接器具体实现"&gt;4.4.2 链接器具体实现&lt;/h3&gt;
&lt;h4 id="链接器实现概述"&gt;链接器实现概述&lt;/h4&gt;
&lt;p&gt;我们在汇编器中，解析了&lt;code&gt;.data&lt;/code&gt;和&lt;code&gt;.text&lt;/code&gt;段，因此我们在这里也将实现一个简化过的链接器，它将把一个或多个.o文件的&lt;code&gt;.data&lt;/code&gt;和&lt;code&gt;.text&lt;/code&gt;合并在一起来创建可执行的机器代码，但是我们不会为其添加ELF文件头，因此你可以认为我们的输出是可执行文件去掉ELF文件头以后的二进制bin文件。
具体的链接步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建一个空的&lt;strong&gt;全局&lt;/strong&gt;符号定义表，这里将存储所有文件中符号（定义位置）的绝对地址，因此每个符号&lt;strong&gt;至多出现一次&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;对于每个目标文件都创建一个&lt;strong&gt;独立的&lt;/strong&gt;重定位表，将包含每个需要重定位符号的相对地址；&lt;/li&gt;
&lt;li&gt;打开每个目标文件，分别读取它的&lt;code&gt;.data&lt;/code&gt;, &lt;code&gt;.text&lt;/code&gt;, &lt;code&gt;.symbol&lt;/code&gt;, &lt;code&gt;.relocation&lt;/code&gt;段：
&lt;ul&gt;
&lt;li&gt;如果是&lt;code&gt;.data&lt;/code&gt;段，读取该文件&lt;code&gt;.data&lt;/code&gt;段的大小，用于计算上述提到的绝对地址；&lt;/li&gt;
&lt;li&gt;如果是&lt;code&gt;.text&lt;/code&gt;段，计算指令数目，得到该文件的指令将会占用多少字节（MIPS 的每条指令固定为 4 字节）；&lt;/li&gt;
&lt;li&gt;如果是&lt;code&gt;.symbol&lt;/code&gt;段，将其读入，将相对地址转换为绝对地址（&lt;strong&gt;怎么做？&lt;/strong&gt;），并合并进第 1 步创建的全局符号表；&lt;/li&gt;
&lt;li&gt;如果是&lt;code&gt;.relocation&lt;/code&gt;段，将其读入进该文件的重定位表，保留其相对地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;打开输出文件；&lt;/li&gt;
&lt;li&gt;再次打开每个目标文件，读取&lt;code&gt;.text&lt;/code&gt;段，通过查找重定位表判断每条指令是否需要重定位，如果需要，使用符号表查找符号的绝对地址，并填入指令的相应字段，最终输出重定向后的指令即可。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="链接器实现"&gt;链接器实现&lt;/h4&gt;
&lt;p&gt;链接器整体调用关系如下：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/f815e944dea614d90544031b8a9a5cad.png" alt="linker"&gt;&lt;/p&gt;
&lt;p&gt;我们在汇编器的重定位表中引入新的结构体&lt;code&gt;RelocData&lt;/code&gt;(定义在&lt;code&gt;linker_utils.h&lt;/code&gt;)，主要是在重定位表中加入：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字段&lt;code&gt;text_size&lt;/code&gt;用于记录该文件的&lt;code&gt;.text&lt;/code&gt;段需要占据的字节数；&lt;/li&gt;
&lt;li&gt;字段&lt;code&gt;data_size&lt;/code&gt;用于记录该文件的&lt;code&gt;.data&lt;/code&gt;段需要占据的字节数；&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SymbolTable &lt;span style="color:#f92672"&gt;*&lt;/span&gt;table; &lt;span style="color:#75715e"&gt;//重定位表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; text_size; &lt;span style="color:#75715e"&gt;//相应文件.text段大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; data_size; &lt;span style="color:#75715e"&gt;//相应文件.data段大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} RelocData;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="测试样例"&gt;测试样例&lt;/h4&gt;
&lt;p&gt;为了便于理解，提供以下样例以供参考：&lt;/p&gt;
&lt;p&gt;有以下两个.s文件需要进行处理：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.s&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-asm" data-lang="asm"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;num: &lt;span style="color:#a6e22e"&gt;.space&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;main:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;la&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$v1&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s1&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$s2&lt;/span&gt;, -&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$a3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;jal&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$ra&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;$sp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;move&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$v0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beq&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$t0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;$0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;j&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;end:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;add.s&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>4.5 测试环境及提交说明</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/275/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/275/</guid><description>&lt;h3 id="提交说明"&gt;提交说明&lt;/h3&gt;
&lt;p&gt;本次实验需要提交的文件只有&lt;code&gt;my_assembler_utils.c&lt;/code&gt;和&lt;code&gt;my_linker_utils.c&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="测试说明"&gt;测试说明&lt;/h3&gt;
&lt;h4 id="测试步骤"&gt;测试步骤&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;实验提供的代码里有针对各平台的辅助文件，将对应的&lt;code&gt;Makefile&lt;/code&gt;和&lt;code&gt;libP4.a&lt;/code&gt;(Windows系统下为&lt;code&gt;libP4.lib&lt;/code&gt;)文件复制到主目录下（即与&lt;code&gt;assembler.c&lt;/code&gt;文件同一目录）；&lt;/li&gt;
&lt;li&gt;在主目录下通过命令行执行&lt;code&gt;make assembler&lt;/code&gt;可以得到汇编器可执行文件，执行&lt;code&gt;make linker&lt;/code&gt;可以得到链接器可执行文件，或执行&lt;code&gt;make&lt;/code&gt;可以一起编译汇编器和链接器。&lt;/li&gt;
&lt;li&gt;创建输入文件，并写入你希望测试的&lt;code&gt;MIPS&lt;/code&gt;汇编代码，之后调用汇编器和链接器完成&lt;code&gt;MIPS&lt;/code&gt;代码到机器码的转换，举例如下：&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Linux系统与Mac系统下：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./assembler main.asm main.int main.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./assembler add.asm add.int add.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./linker main.out add.out main.o 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Windows系统下：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;assembler.exe main.asm main.int main.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;assembler.exe add.asm add.int add.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;linker.exe main.out add.out main.o 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;我们提供了各平台下的标准汇编器和链接器文件，以供大家作为参考。&lt;/li&gt;
&lt;li&gt;我们还提供了CPU处理器用于运行机器码并观察结果，使用指南在下一章节。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="测试环境"&gt;测试环境&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Windows: 可以通过&lt;a href="https://blog.csdn.net/fengyuyeguirenenen/article/details/129162492"&gt;这篇教程&lt;/a&gt;安装&lt;code&gt;MinGW-64&lt;/code&gt;来执行&lt;code&gt;make&lt;/code&gt;，注意需要配置系统变量，并拷贝一个&lt;code&gt;mingw32-make.exe&lt;/code&gt;的副本命名为&lt;code&gt;make.exe&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Linux: 直接安装&lt;code&gt;gcc&lt;/code&gt;即可。&lt;/li&gt;
&lt;li&gt;Mac: 直接安装&lt;code&gt;gcc&lt;/code&gt;即可。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>4.5 测试环境及提交说明</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/984/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/984/</guid><description>&lt;h3 id="提交说明"&gt;提交说明&lt;/h3&gt;
&lt;p&gt;本次实验需要提交的文件只有&lt;code&gt;my_assembler_utils.c&lt;/code&gt;和&lt;code&gt;my_linker_utils.c&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="测试说明"&gt;测试说明&lt;/h3&gt;
&lt;h4 id="测试步骤"&gt;测试步骤&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;实验提供的代码里有针对各平台的辅助文件，将对应的&lt;code&gt;Makefile&lt;/code&gt;和&lt;code&gt;libP4.a&lt;/code&gt;(Windows系统下为&lt;code&gt;libP4.lib&lt;/code&gt;)文件复制到主目录下（即与&lt;code&gt;assembler.c&lt;/code&gt;文件同一目录）；&lt;/li&gt;
&lt;li&gt;在主目录下通过命令行执行&lt;code&gt;make assembler&lt;/code&gt;可以得到汇编器可执行文件，执行&lt;code&gt;make linker&lt;/code&gt;可以得到链接器可执行文件，或执行&lt;code&gt;make&lt;/code&gt;可以一起编译汇编器和链接器。&lt;/li&gt;
&lt;li&gt;创建输入文件，并写入你希望测试的&lt;code&gt;MIPS&lt;/code&gt;汇编代码，之后调用汇编器和链接器完成&lt;code&gt;MIPS&lt;/code&gt;代码到机器码的转换，举例如下：&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Linux系统与Mac系统下：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./assembler main.asm main.int main.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./assembler add.asm add.int add.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./linker main.out add.out main.o 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Windows系统下：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;assembler.exe main.asm main.int main.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;assembler.exe add.asm add.int add.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;linker.exe main.out add.out main.o 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;我们提供了各平台下的标准汇编器和链接器文件，以供大家作为参考。&lt;/li&gt;
&lt;li&gt;我们还提供了CPU处理器用于运行机器码并观察结果，使用指南在下一章节。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="测试环境"&gt;测试环境&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Windows: 可以通过这篇教程（&lt;a href="https://blog.csdn.net/fengyuyeguirenenen/article/details/129162492"&gt;若打不开请复制网址到导航栏&lt;/a&gt; ）安装&lt;code&gt;MinGW-64&lt;/code&gt;来执行&lt;code&gt;make&lt;/code&gt;，注意需要配置系统变量，并拷贝一个&lt;code&gt;mingw32-make.exe&lt;/code&gt;的副本命名为&lt;code&gt;make.exe&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Linux: 直接安装&lt;code&gt;gcc&lt;/code&gt;即可。&lt;/li&gt;
&lt;li&gt;Mac: 直接安装&lt;code&gt;gcc&lt;/code&gt;即可。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>4.6 CPU使用指南</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/276/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/276/</guid><description>&lt;blockquote&gt;
&lt;p&gt;李宇衡 &lt;a href="mailto:liyuheng55555@126.com"&gt;liyuheng55555@126.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="前言"&gt;前言&lt;/h3&gt;
&lt;p&gt;这个CPU大体上和理论课讲过的单周期CPU差不多，就多一些细节，相信大家看一眼就知道怎么用，多看几眼就看明白结构了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意使用本次实验提供的2.16版logisim来打开&lt;/strong&gt;，据测试jdk8也是能跑的，助教本地的jdk15也可以，要是jdk17、18就更没问题了。用logisim2.7可能CPU不能正常运行。&lt;/p&gt;
&lt;p&gt;CPU支持的指令与指导书同步，因此不要测试超出的指令，可能会导致CPU无法识别而出现问题。&lt;/p&gt;
&lt;p&gt;对于&lt;code&gt;syscall&lt;/code&gt;系统调用，CPU仅支持用其停止程序，不支持任何输入输出，因此为了在CPU里调试，需要对MIPS代码进行一些修改：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于简单的数字输入，可以直接使用&lt;code&gt;li&lt;/code&gt;指令写入寄存器；&lt;/li&gt;
&lt;li&gt;对于数字输出，可以将其存储到RAM的某一地址，在CPU停机后进行观察。
如下所示：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;.data

.text
main:
 li $a0, 100200
 li $a1, -209
 jal add
 sw $v0, 0($zero)
 li $v0, 10
 syscall
add:
 add $v0, $a0, $a1
 jr $ra
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果你的汇编链接器实现正确，那么导入机器码并运行CPU停机后，会在内存地址第0行看到&lt;code&gt;0x00018697&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="如何使用"&gt;如何使用&lt;/h3&gt;
&lt;p&gt;使用CPU的操作可以概括为：&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;编写汇编程序，用MARS或者自己的汇编链接器生成机器码；&lt;/li&gt;
&lt;li&gt;向CPU中的指令rom加载机器码；&lt;/li&gt;
&lt;li&gt;用&lt;code&gt;ctrl+k&lt;/code&gt;连续运行，或者用&lt;code&gt;ctrl+t&lt;/code&gt;单步运行；&lt;/li&gt;
&lt;li&gt;停机后，查看内存中的运行结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="导入机器码"&gt;导入机器码&lt;/h3&gt;
&lt;h4 id="用mars导出机器码"&gt;用MARS导出机器码&lt;/h4&gt;
&lt;p&gt;在&lt;code&gt;MARS&lt;/code&gt;编写好代码并汇编完成之后，选择上方工具栏&lt;code&gt;Dump&lt;/code&gt;功能，如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/e0b54859a4f6d92b3cd60d36d372f6e6.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;之后在&lt;code&gt;Dump Format&lt;/code&gt;里选择&lt;code&gt;Hexadecimal Text&lt;/code&gt;并导出，就可以得到与我们的汇编链接器输出的同样格式的十六进制机器码了。&lt;/p&gt;
&lt;h4 id="将机器码导入rom"&gt;将机器码导入ROM&lt;/h4&gt;
&lt;p&gt;为了使用CPU处理器，我们需要将机器码导入ROM，也就是指令存储器。&lt;/p&gt;
&lt;p&gt;首先，在我们自己的汇编链接器生成的机器码文件或者MARS导出的机器码文件的开头，加上一行&lt;code&gt;v2.0 raw&lt;/code&gt;，如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;v2.0 raw
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3c010000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;34230000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2411000a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;24120014&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acff0000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acf1fffc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acf2fff8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0007e821
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0c000c0d
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8fbf0000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00024021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;11000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;08000c0d
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8fb5fffc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8fb6fff8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;02b64021
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00081021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;03e00008
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后找到ROM，右键点击并选择&amp;rsquo;加载数据镜像&amp;rsquo;，最后选择刚刚的机器码文件即可。&lt;/p&gt;</description></item><item><title>4.6 CPU使用指南</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/985/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/985/</guid><description>&lt;blockquote&gt;
&lt;p&gt;李宇衡 &lt;a href="mailto:liyuheng55555@126.com"&gt;liyuheng55555@126.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="前言"&gt;前言&lt;/h3&gt;
&lt;p&gt;这个CPU大体上和理论课讲过的单周期CPU差不多，就多一些细节，相信大家看一眼就知道怎么用，多看几眼就看明白结构了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意使用本次实验提供的2.16版logisim来打开&lt;/strong&gt;，据测试jdk8也是能跑的，助教本地的jdk15也可以，要是jdk17、18就更没问题了。用logisim2.7可能CPU不能正常运行。&lt;/p&gt;
&lt;p&gt;CPU支持的指令与指导书同步，因此不要测试超出的指令，可能会导致CPU无法识别而出现问题。&lt;/p&gt;
&lt;p&gt;对于&lt;code&gt;syscall&lt;/code&gt;系统调用，CPU仅支持用其停止程序，不支持任何输入输出，因此为了在CPU里调试，需要对MIPS代码进行一些修改：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于简单的数字输入，可以直接使用&lt;code&gt;li&lt;/code&gt;指令写入寄存器；&lt;/li&gt;
&lt;li&gt;对于数字输出，可以将其存储到RAM的某一地址，在CPU停机后进行观察。
如下所示：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;.data

.text
main:
 li $a0, 100200
 li $a1, -209
 jal add
 sw $v0, 0($zero)
 li $v0, 10
 syscall
add:
 add $v0, $a0, $a1
 jr $ra
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果你的汇编链接器实现正确，那么导入机器码并运行CPU停机后，会在内存地址第0行看到&lt;code&gt;0x00018697&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="如何使用"&gt;如何使用&lt;/h3&gt;
&lt;p&gt;使用CPU的操作可以概括为：&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;编写汇编程序，用MARS或者自己的汇编链接器生成机器码；&lt;/li&gt;
&lt;li&gt;向CPU中的指令rom加载机器码；&lt;/li&gt;
&lt;li&gt;用&lt;code&gt;ctrl+k&lt;/code&gt;连续运行，或者用&lt;code&gt;ctrl+t&lt;/code&gt;单步运行；&lt;/li&gt;
&lt;li&gt;停机后，查看内存中的运行结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="导入机器码"&gt;导入机器码&lt;/h3&gt;
&lt;h4 id="用mars导出机器码"&gt;用MARS导出机器码&lt;/h4&gt;
&lt;p&gt;在&lt;code&gt;MARS&lt;/code&gt;编写好代码并汇编完成之后，选择上方工具栏&lt;code&gt;Dump&lt;/code&gt;功能，如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/e0b54859a4f6d92b3cd60d36d372f6e6.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;之后在&lt;code&gt;Dump Format&lt;/code&gt;里选择&lt;code&gt;Hexadecimal Text&lt;/code&gt;并导出，就可以得到与我们的汇编链接器输出的同样格式的十六进制机器码了。&lt;/p&gt;
&lt;h4 id="将机器码导入rom"&gt;将机器码导入ROM&lt;/h4&gt;
&lt;p&gt;为了使用CPU处理器，我们需要将机器码导入ROM，也就是指令存储器。&lt;/p&gt;
&lt;p&gt;首先，在我们自己的汇编链接器生成的机器码文件或者MARS导出的机器码文件的开头，加上一行&lt;code&gt;v2.0 raw&lt;/code&gt;，如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;v2.0 raw
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3c010000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;34230000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2411000a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;24120014&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acff0000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acf1fffc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acf2fff8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0007e821
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0c000c0d
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8fbf0000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00024021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;11000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;08000c0d
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8fb5fffc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8fb6fff8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;02b64021
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00081021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;03e00008
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后找到ROM，右键点击并选择&amp;rsquo;加载数据镜像&amp;rsquo;，最后选择刚刚的机器码文件即可。&lt;/p&gt;</description></item><item><title>Logisim使用指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/233/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/233/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Logisim使用指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h1 cid="n175" class="md-end-block md-heading md-focus" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 2.2rem;margin-top: 1rem;margin-bottom: 1rem;position: relative;line-height: 1.3;cursor: text;padding-bottom: 0.4rem;white-space: pre-wrap;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box"&gt;走进Logisim&lt;/span&gt;&lt;/h1&gt;&lt;p cid="n176" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;学习软件开发，你可能第一时间想到的是：&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box;padding: 0px 1px"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;C&lt;/span&gt; &lt;span md-inline="plain" style="box-sizing: border-box"&gt;语言、Java、Python、数据结构、前端后端、算法等等&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;，没错，这些技术都是软件开发的关键技术，这些将来大家都会学习。然而，想成为一名优秀的软件工程师，仅仅掌握软件方面的知识，&lt;/span&gt; &lt;span md-inline="plain" style="box-sizing: border-box"&gt;是完全不够的。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Logisim使用指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/904/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/904/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Logisim使用指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h1 cid="n175" class="md-end-block md-heading md-focus" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 2.2rem;margin-top: 1rem;margin-bottom: 1rem;position: relative;line-height: 1.3;cursor: text;padding-bottom: 0.4rem;white-space: pre-wrap;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box"&gt;走进Logisim&lt;/span&gt;&lt;/h1&gt;&lt;p cid="n176" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;学习软件开发，你可能第一时间想到的是：&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box;padding: 0px 1px"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;C&lt;/span&gt; &lt;span md-inline="plain" style="box-sizing: border-box"&gt;语言、Java、Python、数据结构、前端后端、算法等等&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;，没错，这些技术都是软件开发的关键技术，这些将来大家都会学习。然而，想成为一名优秀的软件工程师，仅仅掌握软件方面的知识，&lt;/span&gt; &lt;span md-inline="plain" style="box-sizing: border-box"&gt;是完全不够的。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Logisim门电路</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/237/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/237/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Logisim门电路&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n2" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif;'&gt;&lt;span class="md-pair-s md-expand" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;门电路是最基本的数字电路元件，以下是几个常见的 Logisim 门电路元件的简介&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;ol cid="n3" class="ol-list list-paddingleft-2" mdtype="list" start="" style='box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif; white-space: normal;'&gt;&lt;li cid="n4" class="md-" mdtype="list_item" style=""&gt;&lt;p cid="n5" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;或门&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Logisim门电路</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/908/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/908/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Logisim门电路&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n2" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif;'&gt;&lt;span class="md-pair-s md-expand" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;门电路是最基本的数字电路元件，以下是几个常见的 Logisim 门电路元件的简介&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;ol cid="n3" class="ol-list list-paddingleft-2" mdtype="list" start="" style='box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif; white-space: normal;'&gt;&lt;li cid="n4" class="md-" mdtype="list_item" style=""&gt;&lt;p cid="n5" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;或门&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Mealy型有限状态机例题</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/242/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/242/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Mealy型有限状态机例题&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3 cid="n155" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.375rem; margin-top: 1.5rem; margin-bottom: 0.5rem; position: relative; color: var(--heading-text-color); cursor: text; line-height: 1.5; white-space: pre-wrap; font-family: Roboto, sans-serif;"&gt;&lt;span style="color: var(--heading-text-color); font-size: 1.375rem;"&gt;实验任务&lt;/span&gt;&lt;br/&gt;&lt;/h3&gt;&lt;p cid="n156" class="md-end-block md-p md-focus" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin: 0.5rem 0rem 1.5rem; white-space: pre-wrap; position: relative; color: rgb(59, 69, 78); font-family: Roboto, sans-serif; font-size: 15.2px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;要求你搭建一个&lt;/span&gt;&lt;span class="md-pair-s md-expand" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;Mealy型状态机&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;解决&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;2^n mod 5&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;的数学问题&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Mealy型有限状态机例题</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/913/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/913/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Mealy型有限状态机例题&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3 cid="n155" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.375rem; margin-top: 1.5rem; margin-bottom: 0.5rem; position: relative; color: var(--heading-text-color); cursor: text; line-height: 1.5; white-space: pre-wrap; font-family: Roboto, sans-serif;"&gt;&lt;span style="color: var(--heading-text-color); font-size: 1.375rem;"&gt;实验任务&lt;/span&gt;&lt;br/&gt;&lt;/h3&gt;&lt;p cid="n156" class="md-end-block md-p md-focus" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin: 0.5rem 0rem 1.5rem; white-space: pre-wrap; position: relative; color: rgb(59, 69, 78); font-family: Roboto, sans-serif; font-size: 15.2px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;要求你搭建一个&lt;/span&gt;&lt;span class="md-pair-s md-expand" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;Mealy型状态机&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;解决&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;2^n mod 5&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;的数学问题&lt;/span&gt;&lt;/p&gt;</description></item><item><title>MIPS汇编指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/232/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/232/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;MIPS汇编指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="box-sizing: border-box;position: absolute"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n2" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;br/&gt;&lt;/p&gt;&lt;p cid="n5" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;在阅读本指导书前，需要你先下载Mars软件并配置java运行环境，具体方式可以查看pdf版指导书《Mars使用教程》。如果你对于mips汇编是完完全全的零基础，那么，欢迎阅读本指导书，我会用最为朴实的语言，最为细致的样例，只讲方法，不讲原理，手把手教你写汇编程序，保证你奶奶来了都能学会。&lt;/span&gt;&lt;/p&gt;&lt;h1 cid="n6" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 2.2rem;margin-top: 1rem;margin-bottom: 1rem;position: relative;line-height: 1.3;cursor: text;padding-bottom: 0.4rem;white-space: pre-wrap;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;入门篇&lt;/span&gt;&lt;/h1&gt;&lt;h3 cid="n7" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 1.4rem;margin: 20px 0px 7px;position: relative;line-height: 1.43;cursor: text;white-space: pre-wrap;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;赋值&lt;/span&gt;&lt;/h3&gt;&lt;p cid="n8" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;在C语言中，我们最先用到的便是给变量赋值，这个在mips中该如何实现呢？&lt;/span&gt;&lt;/p&gt;</description></item><item><title>MIPS汇编指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/905/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/905/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;MIPS汇编指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="box-sizing: border-box;position: absolute"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n2" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;br/&gt;&lt;/p&gt;&lt;p cid="n5" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;在阅读本指导书前，需要你先下载Mars软件并配置java运行环境，具体方式可以查看pdf版指导书《Mars使用教程》。如果你对于mips汇编是完完全全的零基础，那么，欢迎阅读本指导书，我会用最为朴实的语言，最为细致的样例，只讲方法，不讲原理，手把手教你写汇编程序，保证你奶奶来了都能学会。&lt;/span&gt;&lt;/p&gt;&lt;h1 cid="n6" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 2.2rem;margin-top: 1rem;margin-bottom: 1rem;position: relative;line-height: 1.3;cursor: text;padding-bottom: 0.4rem;white-space: pre-wrap;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;入门篇&lt;/span&gt;&lt;/h1&gt;&lt;h3 cid="n7" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 1.4rem;margin: 20px 0px 7px;position: relative;line-height: 1.43;cursor: text;white-space: pre-wrap;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;赋值&lt;/span&gt;&lt;/h3&gt;&lt;p cid="n8" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: 1.6rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;word-spacing: 0.05rem;caret-color: rgb(52, 73, 94);color: rgb(52, 73, 94);font-family: Ubuntu, 'Source Sans Pro', sans-serif;background-color: rgb(255, 255, 255)"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;在C语言中，我们最先用到的便是给变量赋值，这个在mips中该如何实现呢？&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Moore型有限状态机例题</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/241/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/241/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Moore型有限状态机例题&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h2 cid="n2" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.7rem; margin-top: 2rem; margin-bottom: 0.5rem; position: relative; color: var(--heading-text-color); cursor: text; line-height: 1.5; white-space: pre-wrap; font-family: Roboto, sans-serif;"&gt;&lt;span style="color: var(--heading-text-color); font-size: 1.375rem;"&gt;实验任务&lt;/span&gt;&lt;br/&gt;&lt;/h2&gt;&lt;p cid="n4" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin: 0.5rem 0rem 1.5rem; white-space: pre-wrap; position: relative; color: rgb(59, 69, 78); font-family: Roboto, sans-serif; font-size: 15.2px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;你需要搭建一个&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;Moore型&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box;"&gt;有限状态机，检测小刘同学是否能连续地数出1、2、3。&lt;/span&gt;&lt;/p&gt;&lt;h3 cid="n5" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.375rem; margin-top: 1.5rem; margin-bottom: 0.5rem; position: relative; color: var(--heading-text-color); cursor: text; line-height: 1.5; white-space: pre-wrap; font-family: Roboto, sans-serif;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;实验具体要求&lt;/span&gt;&lt;/h3&gt;&lt;p cid="n6" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin: 0.5rem 0rem 1.5rem; white-space: pre-wrap; position: relative; color: rgb(59, 69, 78); font-family: Roboto, sans-serif; font-size: 15.2px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;小刘同学在每个时钟上升沿到来时说1、2、3中的任意一个数，由于小刘同学比较笨，他可能连续几次说出同一个数，只要总体顺序没错，我们原谅他。只要他能顺序不错地最终数出1、2、3的顺序正确的序列（例如“1 1 1 2 2 3 3 3 3”、“1 2 3”、“1 2 3 3”……，即文法满足：“&amp;lt;若干个1&amp;gt;&amp;lt;若干个2&amp;gt;&amp;lt;若干个3&amp;gt;”），就算对（输出1）！&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Moore型有限状态机例题</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/912/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/912/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;Moore型有限状态机例题&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h2 cid="n2" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.7rem; margin-top: 2rem; margin-bottom: 0.5rem; position: relative; color: var(--heading-text-color); cursor: text; line-height: 1.5; white-space: pre-wrap; font-family: Roboto, sans-serif;"&gt;&lt;span style="color: var(--heading-text-color); font-size: 1.375rem;"&gt;实验任务&lt;/span&gt;&lt;br/&gt;&lt;/h2&gt;&lt;p cid="n4" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin: 0.5rem 0rem 1.5rem; white-space: pre-wrap; position: relative; color: rgb(59, 69, 78); font-family: Roboto, sans-serif; font-size: 15.2px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;你需要搭建一个&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;Moore型&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box;"&gt;有限状态机，检测小刘同学是否能连续地数出1、2、3。&lt;/span&gt;&lt;/p&gt;&lt;h3 cid="n5" class="md-end-block md-heading" mdtype="heading" style="box-sizing: border-box; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.375rem; margin-top: 1.5rem; margin-bottom: 0.5rem; position: relative; color: var(--heading-text-color); cursor: text; line-height: 1.5; white-space: pre-wrap; font-family: Roboto, sans-serif;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;实验具体要求&lt;/span&gt;&lt;/h3&gt;&lt;p cid="n6" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin: 0.5rem 0rem 1.5rem; white-space: pre-wrap; position: relative; color: rgb(59, 69, 78); font-family: Roboto, sans-serif; font-size: 15.2px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;小刘同学在每个时钟上升沿到来时说1、2、3中的任意一个数，由于小刘同学比较笨，他可能连续几次说出同一个数，只要总体顺序没错，我们原谅他。只要他能顺序不错地最终数出1、2、3的顺序正确的序列（例如“1 1 1 2 2 3 3 3 3”、“1 2 3”、“1 2 3 3”……，即文法满足：“&amp;lt;若干个1&amp;gt;&amp;lt;若干个2&amp;gt;&amp;lt;若干个3&amp;gt;”），就算对（输出1）！&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Valgrind与Cache评测</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/259/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/259/</guid><description>&lt;p&gt;本实验应用了Valgrind这一强大的工具来辅助我们完成Cache的设计与评测，为了方便同学们理解memory trace（即我们所说的内存访问记录），并理解我们如何获取矩阵转置函数的内存访问记录，我们对Valgrind和实验中的评测代码进行进一步的说明（&lt;strong&gt;此部分不理解完全不影响实验的完成，只需成功安装Valgrind用于本地实验评测即可&lt;/strong&gt;）。&lt;/p&gt;
&lt;h3 id="valgrind简介"&gt;Valgrind简介&lt;/h3&gt;
&lt;p&gt;Valgrind 是运行在Linux 上的多用途代码剖析和内存调试软件。主要包括Memcheck、Callgrind、Cachegrind 等工具，每个工具都能完成一项任务调试、检测或分析。可以检测内存泄漏、线程违例和Cache 的使用等。Valgrind 基于仿真方式对程序进行调试，它先于应用程序获取实际处理器的控制权，并在实际处理器的基础上仿真一个虚拟处理器，并使应用程序运行于这个虚拟处理器之上，从而对应用程序的运行进行监视。应用程序并不知道该处理器是虚拟的还是实际的，已经编译成二进制代码的应用程序并不用重新进行编译，Valgrind 直接解释二进制代码使得应用程序基于它运行，从而能够检查内存操作时可能出现的错误。&lt;/p&gt;
&lt;h4 id="valgrind的安装"&gt;Valgrind的安装&lt;/h4&gt;
&lt;p&gt;由于valgrind没有提供Windows版本，因此建议是使用Linux系统（可以使用虚拟机）来进行相关的调试。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关于Mac：官方的valgrind不支持Mac或对Mac后续版本支持的不好，需要安装Mac的镜像版本，可以在github上找到：https://github.com/LouisBrunner/valgrind-macos&lt;/p&gt;
&lt;p&gt;在安装时遇到的常见问题，可以参考博文：https://zhuanlan.zhihu.com/p/508470880&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;笔者用的是ubuntu，在ubuntu下&lt;strong&gt;直接使用系统包管理工具即可安装&lt;/strong&gt;（无特殊需要建议直接以此方式安装）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install valgrind
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果有特定需求需要安装一些其他版本，可以进入valgrind官网，下载对应的源码并make安装（&lt;strong&gt;本实验不推荐此种安装方式&lt;/strong&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;首先是进入官网下载对应版本：http://valgrind.org/downloads/valgrind-3.12.0.tar.bz2&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后解压缩：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -jxvf valgrind-3.14.0.tar.bz2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进入目录,进行安装,其中/home/user1/valgrind是你想安装的目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd valgrind-3.14.0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/user1/valgrind
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;配置环境变量，首先打开~/.bashrc，将下面一段话加入该文件，路径即为安装目录下bin目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PATH:~/valgrind/bin/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使改变生效：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="valgrind的使用"&gt;Valgrind的使用&lt;/h4&gt;
&lt;p&gt;valgrind的使用可以简要概括为以下表示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;valgrind &lt;span style="color:#f92672"&gt;[&lt;/span&gt;valgrind-options&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &amp;lt;your-prog&amp;gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;your-prog-options&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;&amp;lt;your-prog&amp;gt; [your-prog-options]&lt;/code&gt;部分是需要进行内存调试的程序执行命令，与在shell命令行中执行命令的方式完全相同。&lt;code&gt;[valgrind-options]&lt;/code&gt;是我们重点需要关注的部分，通过这些options我们得以应用valgrind的功能。valgrind提供了丰富的调试选项，以下列出一些常用的选项。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--tool=&amp;lt;toolname&amp;gt; [default: memcheck]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;最核心的命令，选择了valgrind当前的工作模式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-h --help&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;与一般的帮助选项相同，可以比较便捷的查看valgrind的命令用法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-v --verbose&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;输出详细信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--log-fd=&amp;lt;number&amp;gt; [default: 2, stderr]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;打印输出访问记录的位置，&lt;code&gt;number&lt;/code&gt;为1表示stdout，&lt;code&gt;number&lt;/code&gt;为2表示stderr，用此命令时一般设&lt;code&gt;number&lt;/code&gt;为1在命令交互界面查看输出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--log-file=&amp;lt;filename&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;与上一条命令类似，但是将记录日志输出到对应的文件中（更加推荐这种方式）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="valgrind在cache评测中的应用"&gt;Valgrind在Cache评测中的应用&lt;/h3&gt;
&lt;h4 id="part1cache的模拟器实现"&gt;Part1：Cache的模拟器实现&lt;/h4&gt;
&lt;p&gt;valgrind可以通过简单的命令生成程序模拟执行过程中产生的记录日志（memory trace）。&lt;/p&gt;
&lt;p&gt;memory trace的格式如下：&lt;/p&gt;</description></item><item><title>Valgrind与Cache评测</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/978/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/978/</guid><description>&lt;p&gt;本实验应用了Valgrind这一强大的工具来辅助我们完成Cache的设计与评测，为了方便同学们理解memory trace（即我们所说的内存访问记录），并理解我们如何获取矩阵转置函数的内存访问记录，我们对Valgrind和实验中的评测代码进行进一步的说明（&lt;strong&gt;此部分不理解完全不影响实验的完成，只需成功安装Valgrind用于本地实验评测即可&lt;/strong&gt;）。&lt;/p&gt;
&lt;h3 id="valgrind简介"&gt;Valgrind简介&lt;/h3&gt;
&lt;p&gt;Valgrind 是运行在Linux 上的多用途代码剖析和内存调试软件。主要包括Memcheck、Callgrind、Cachegrind 等工具，每个工具都能完成一项任务调试、检测或分析。可以检测内存泄漏、线程违例和Cache 的使用等。Valgrind 基于仿真方式对程序进行调试，它先于应用程序获取实际处理器的控制权，并在实际处理器的基础上仿真一个虚拟处理器，并使应用程序运行于这个虚拟处理器之上，从而对应用程序的运行进行监视。应用程序并不知道该处理器是虚拟的还是实际的，已经编译成二进制代码的应用程序并不用重新进行编译，Valgrind 直接解释二进制代码使得应用程序基于它运行，从而能够检查内存操作时可能出现的错误。&lt;/p&gt;
&lt;h4 id="valgrind的安装"&gt;Valgrind的安装&lt;/h4&gt;
&lt;p&gt;由于valgrind没有提供Windows版本，因此建议是使用Linux系统（可以使用虚拟机）来进行相关的调试。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关于Mac：官方的valgrind不支持Mac或对Mac后续版本支持的不好，需要安装Mac的镜像版本，可以在github上找到：https://github.com/LouisBrunner/valgrind-macos&lt;/p&gt;
&lt;p&gt;在安装时遇到的常见问题，可以参考博文：https://zhuanlan.zhihu.com/p/508470880&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;笔者用的是ubuntu，在ubuntu下&lt;strong&gt;直接使用系统包管理工具即可安装&lt;/strong&gt;（无特殊需要建议直接以此方式安装）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install valgrind
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果有特定需求需要安装一些其他版本，可以进入valgrind官网，下载对应的源码并make安装（&lt;strong&gt;本实验不推荐此种安装方式&lt;/strong&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;首先是进入官网下载对应版本：https://sourceware.org/pub/valgrind/valgrind-3.12.0.tar.bz2&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后解压缩：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -jxvf valgrind-3.14.0.tar.bz2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进入目录,进行安装,其中/home/user1/valgrind是你想安装的目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd valgrind-3.14.0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/user1/valgrind
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;配置环境变量，首先打开~/.bashrc，将下面一段话加入该文件，路径即为安装目录下bin目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PATH:~/valgrind/bin/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使改变生效：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="valgrind的使用"&gt;Valgrind的使用&lt;/h4&gt;
&lt;p&gt;valgrind的使用可以简要概括为以下表示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;valgrind &lt;span style="color:#f92672"&gt;[&lt;/span&gt;valgrind-options&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &amp;lt;your-prog&amp;gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;your-prog-options&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;&amp;lt;your-prog&amp;gt; [your-prog-options]&lt;/code&gt;部分是需要进行内存调试的程序执行命令，与在shell命令行中执行命令的方式完全相同。&lt;code&gt;[valgrind-options]&lt;/code&gt;是我们重点需要关注的部分，通过这些options我们得以应用valgrind的功能。valgrind提供了丰富的调试选项，以下列出一些常用的选项。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--tool=&amp;lt;toolname&amp;gt; [default: memcheck]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;最核心的命令，选择了valgrind当前的工作模式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-h --help&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;与一般的帮助选项相同，可以比较便捷的查看valgrind的命令用法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-v --verbose&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;输出详细信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--log-fd=&amp;lt;number&amp;gt; [default: 2, stderr]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;打印输出访问记录的位置，&lt;code&gt;number&lt;/code&gt;为1表示stdout，&lt;code&gt;number&lt;/code&gt;为2表示stderr，用此命令时一般设&lt;code&gt;number&lt;/code&gt;为1在命令交互界面查看输出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--log-file=&amp;lt;filename&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;与上一条命令类似，但是将记录日志输出到对应的文件中（更加推荐这种方式）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="valgrind在cache评测中的应用"&gt;Valgrind在Cache评测中的应用&lt;/h3&gt;
&lt;h4 id="part1cache的模拟器实现"&gt;Part1：Cache的模拟器实现&lt;/h4&gt;
&lt;p&gt;valgrind可以通过简单的命令生成程序模拟执行过程中产生的记录日志（memory trace）。&lt;/p&gt;
&lt;p&gt;memory trace的格式如下：&lt;/p&gt;</description></item><item><title>入门篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/250/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/250/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;入门篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 的指令非常多，指导书当中也只会列举出完成实验常用的指令。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在课件下载区新增了《MIPS32-Quick Reference》，是常用 MIPS 指令的快速查询手册。&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:center"&gt;&lt;img alt="MIPS32-Quick Reference.pdf.png" height="604" src="../images/1699092402113036840.png" style="width: 852px; height: 604px;" title="1699092402113036840.png" width="852"/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 汇编编写的主要的一个难点就是，一次只能做一个运算，但是会用到好几个寄存器，稍微复杂一点就乱了。我的建议是对每一个使用到的寄存器，都做上注释防止出现混乱。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;另外，希望大家在写 MIPS 汇编的时候，多多参考 MARS Help 当中的内容。&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:center"&gt;&lt;img alt="截屏2023-11-04 14.44.14.png" height="509" src="../images/1699092372361056346.png" style="width: 647px; height: 509px;" title="1699092372361056346.png" width="647"/&gt;&lt;/p&gt;&lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;赋值&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在 C 语言中，我们最先用到的便是给变量赋值，这个在 MIPS 中该如何实现呢？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;下面这条指令的意思，就是将 t1 寄存器的值赋值为 100，其实际含义是给 $t1 赋值为 100 和 0 进行按位或运算后得到的结果。&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; ori $t1, 100&lt;br/&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;当然了，我们也可以使用扩展指令（伪指令）li（load immediate），下面这条指令的意思，便是直接将 $t1 寄存器赋值为 100，该指令与上一条指令的效果完全一致。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>入门篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/917/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/917/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;入门篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 的指令非常多，指导书当中也只会列举出完成实验常用的指令。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在课件下载区新增了《MIPS32-Quick Reference》，是常用 MIPS 指令的快速查询手册。&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:center"&gt;&lt;img alt="MIPS32-Quick Reference.pdf.png" height="604" src="../images/621dc19d9e3af4d1eb5383d52414fd70.png" style="width: 852px; height: 604px;" title="1699092402113036840.png" width="852"/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 汇编编写的主要的一个难点就是，一次只能做一个运算，但是会用到好几个寄存器，稍微复杂一点就乱了。我的建议是对每一个使用到的寄存器，都做上注释防止出现混乱。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;另外，希望大家在写 MIPS 汇编的时候，多多参考 MARS Help 当中的内容。&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:center"&gt;&lt;img alt="截屏2023-11-04 14.44.14.png" height="509" src="../images/3c56e7b75da77ccb7e91bd7928029ad7.png" style="width: 647px; height: 509px;" title="1699092372361056346.png" width="647"/&gt;&lt;/p&gt;&lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;赋值&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在 C 语言中，我们最先用到的便是给变量赋值，这个在 MIPS 中该如何实现呢？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;下面这条指令的意思，就是将 t1 寄存器的值赋值为 100，其实际含义是给 $t1 赋值为 100 和 0 进行按位或运算后得到的结果。&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; ori $t1, 100&lt;br/&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;当然了，我们也可以使用扩展指令（伪指令）li（load immediate），下面这条指令的意思，便是直接将 $t1 寄存器赋值为 100，该指令与上一条指令的效果完全一致。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>写在最后</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/253/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/253/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;写在最后&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;以上便是 MIPS 汇编中一些最主要的编码方法，需要你能够在完全理解的基础上，多多练习，方能融会贯通。如果想要对 MIPS 汇编的原理进行更深一步的了解，可以阅读本课程相应的 PDF 版指导书。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;最后，感谢高远同学为课程组提供了“MIPS 教程”详细的指导书。今年胡峻诚同学在他的教程的基础上，扩充了部分内容。另外，由于高远同学今年不在担任本课程的助教，所以如果发现了本指导书的错误，或是对某些地方产生疑问，欢迎各位同学在计算机硬件基础群中添加助教的微信反馈。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>写在最后</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/921/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/921/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;写在最后&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;以上便是 MIPS 汇编中一些最主要的编码方法，需要你能够在完全理解的基础上，多多练习，方能融会贯通。如果想要对 MIPS 汇编的原理进行更深一步的了解，可以阅读本课程相应的 PDF 版指导书。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;最后，感谢高远同学为课程组提供了“MIPS 教程”详细的指导书。今年胡峻诚同学在他的教程的基础上，扩充了部分内容。另外，由于高远同学今年不在担任本课程的助教，所以如果发现了本指导书的错误，或是对某些地方产生疑问，欢迎各位同学在计算机硬件基础群中添加助教的微信反馈。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>基础篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/251/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/251/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;基础篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;一次简单的 if 条件判断&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在 C 语言中，常用 if 结构，在 MIPS 中如何实现呢？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;考虑下面的代码：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; if (a &amp;gt; 5) {&lt;br/&gt;   // do A;&lt;br&gt; }&lt;br/&gt; // do B;&lt;br/&gt;&lt;/br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;我们不得不提一个叫做 ble 的指令，如下图，其含义是若 $t1 寄存器的值小于等于 5，则跳转到 label 标签处；否则，执行 ble 的下一条指令。&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; ble $t1, 5, label&lt;br/&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;所以我们需要给源程序打上标签：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; if (a &amp;gt; 5) {&lt;br/&gt;   // do A;&lt;br/&gt; }&lt;br/&gt; // label:&lt;br/&gt; // do B;&lt;br/&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;经过这样打标签之后，程序的逻辑就变成了：&lt;/span&gt;&lt;/p&gt;</description></item><item><title>基础篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/918/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/918/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;基础篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;一次简单的 if 条件判断&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在 C 语言中，常用 if 结构，在 MIPS 中如何实现呢？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;考虑下面的代码：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; if (a &amp;gt; 5) {&lt;br/&gt;   // do A;&lt;br&gt; }&lt;br/&gt; // do B;&lt;br/&gt;&lt;/br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;我们不得不提一个叫做 ble 的指令，如下图，其含义是若 $t1 寄存器的值小于等于 5，则跳转到 label 标签处；否则，执行 ble 的下一条指令。&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; ble $t1, 5, label&lt;br/&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;所以我们需要给源程序打上标签：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; if (a &amp;gt; 5) {&lt;br/&gt;   // do A;&lt;br/&gt; }&lt;br/&gt; // label:&lt;br/&gt; // do B;&lt;br/&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;经过这样打标签之后，程序的逻辑就变成了：&lt;/span&gt;&lt;/p&gt;</description></item><item><title>实验1 - 简单部件与状态机设计</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/236/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/236/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验1 - 简单部件与状态机设计&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 16px;'&gt;    本篇教程将会结合logisim向大家介绍数字电路中的门电路、组合逻辑、时序逻辑、有限状态机的相关原理和实现。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 16px;'&gt;    关于本教程的一切问题，请联系@助教-&lt;span style="color: #333333; font-family: arial, helvetica, sans-serif; background-color: #F9F9F9;"&gt;李彦埙&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验1 - 简单部件与状态机设计</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/907/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/907/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验1 - 简单部件与状态机设计&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 16px;'&gt;    本篇教程将会结合logisim向大家介绍数字电路中的门电路、组合逻辑、时序逻辑、有限状态机的相关原理和实现。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 16px;'&gt;    关于本教程的问题，请联系logisim负责助教@助教-&lt;/span&gt;&lt;span style="font-size: 16px; background-color: #F9F9F9;"&gt;&lt;font color="#333333" face="arial, helvetica, sans-serif"&gt;李佳璐&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验2 - MIPS 汇编实验指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/247/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/247/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验2 - MIPS 汇编实验指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在阅读本指导书前，需要你先下载 MARS 软件并配置 java 运行环境，具体方式可以查看 PDF 版指导书《MARS 使用教程》。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;如果你对于 MIPS 汇编是完完全全的零基础，那么，欢迎阅读本指导书，尽力使用最为朴实的语言、最为细致的样例，突出方法，尽可能少的涉及原理，手把手教你写汇编程序。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验2 - MIPS 汇编实验指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/914/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/914/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验2 - MIPS 汇编实验指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;在阅读本指导书前，需要你先下载 MARS 软件并配置 java 运行环境，具体方式可以查看 PDF 版指导书《MARS 使用教程》。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;如果你对于 MIPS 汇编是完完全全的零基础，那么，欢迎阅读本指导书，尽力使用最为朴实的语言、最为细致的样例，突出方法，尽可能少的涉及原理，手把手教你写汇编程序。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验3 - 模拟Cache设计</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/255/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/255/</guid><description>&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;本次实验的相关代码请在【课程信息】--&amp;gt;【课件下载】区域下载获得。&lt;/p&gt;&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;本指导书包含Cache的理论介绍先导和实验题目的具体说明，建议阅读顺序如下：&lt;/span&gt;&lt;/p&gt;&lt;ul class="ul-list list-paddingleft-2" cid="n3" mdtype="list" data-mark="-" style="box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif; white-space: normal;"&gt;&lt;li&gt;&lt;p cid="n5" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;阅读第一章&lt;/span&gt;&lt;span md-inline="strong" class="md-pair-s " style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;高速缓存简介&lt;/strong&gt;&lt;/span&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;，对基本的Cache结构有一定理论上的掌握。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>实验3 - 模拟Cache设计</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/974/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/974/</guid><description>&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;本次实验的相关代码请在【课程信息】--&amp;gt;【课件下载】区域下载获得。&lt;/p&gt;&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;本指导书包含Cache的理论介绍先导和实验题目的具体说明，建议阅读顺序如下：&lt;/span&gt;&lt;/p&gt;&lt;ul class="ul-list list-paddingleft-2" cid="n3" mdtype="list" data-mark="-" style="box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif; white-space: normal;"&gt;&lt;li&gt;&lt;p cid="n5" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;阅读第一章&lt;/span&gt;&lt;span md-inline="strong" class="md-pair-s " style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;高速缓存简介&lt;/strong&gt;&lt;/span&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;，对基本的Cache结构有一定理论上的掌握。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>实验4 - 汇编链接器实现</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/269/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/269/</guid><description>&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; word-break: break-all; color: rgb(51, 51, 51); font-size: 14px; white-space: pre-wrap; background-color: rgb(249, 249, 249); line-height: inherit; orphans: 4; position: relative; font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;本次实验的相关代码请在【课程信息】--&amp;gt;【课件下载】区域下载获得。&lt;/p&gt;&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; word-break: break-all; color: rgb(51, 51, 51); font-size: 14px; white-space: pre-wrap; background-color: rgb(249, 249, 249); line-height: inherit; orphans: 4; position: relative; font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;本指导书包含汇编器和链接器的理论介绍先导和实验题目的具体说明，建议阅读顺序如下：&lt;/span&gt;&lt;/p&gt;</description></item><item><title>实验4 - 汇编链接器实现</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/979/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/979/</guid><description>&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; word-break: break-all; color: rgb(51, 51, 51); font-size: 14px; white-space: pre-wrap; background-color: rgb(249, 249, 249); line-height: inherit; orphans: 4; position: relative; font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;本次实验的相关代码请在【课程信息】--&amp;gt;【课件下载】区域下载获得。&lt;/p&gt;&lt;p cid="n2" mdtype="paragraph" class="md-end-block md-p" style="box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; word-break: break-all; color: rgb(51, 51, 51); font-size: 14px; white-space: pre-wrap; background-color: rgb(249, 249, 249); line-height: inherit; orphans: 4; position: relative; font-family: &amp;quot;Open Sans&amp;quot;, &amp;quot;Clear Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Segoe UI Emoji&amp;quot;, sans-serif;"&gt;&lt;span md-inline="plain" class="md-plain" style="box-sizing: border-box;"&gt;本指导书包含汇编器和链接器的理论介绍先导和实验题目的具体说明，建议阅读顺序如下：&lt;/span&gt;&lt;/p&gt;</description></item><item><title>实验内容</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/248/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/248/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验内容&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;汇编语言是使用符号格式表示指令，可直接面向机器内存以及寄存器的程序设计语言。本部分主要学习内容包括：&lt;/span&gt;&lt;/p&gt;&lt;ol class="list-paddingleft-2"&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;以 MIPS 指令系统为例，学习 MIPS 指令集及汇编语言，能够使用 MIPS 汇编语言编写顺序、分支、循环等具有特定功能的结构化汇编程序，最好能掌握函数调用及栈操作等汇编程序设计方法。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;熟练使用 MARS 工具软件，具备 MARS 调试汇编代码的能力，能使用 MARS 模拟 CPU 执行汇编指令，通过观察相应寄存器、存储等部件的变化情况，查看程序是否符合期望。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验内容</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/915/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/915/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验内容&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;汇编语言是使用符号格式表示指令，可直接面向机器内存以及寄存器的程序设计语言。本部分主要学习内容包括：&lt;/span&gt;&lt;/p&gt;&lt;ol class="list-paddingleft-2"&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;以 MIPS 指令系统为例，学习 MIPS 指令集及汇编语言，能够使用 MIPS 汇编语言编写顺序、分支、循环等具有特定功能的结构化汇编程序，最好能掌握函数调用及栈操作等汇编程序设计方法。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;熟练使用 MARS 工具软件，具备 MARS 调试汇编代码的能力，能使用 MARS 模拟 CPU 执行汇编指令，通过观察相应寄存器、存储等部件的变化情况，查看程序是否符合期望。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验预习指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/231/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/231/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验预习指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700; text-wrap: wrap;"&gt;数制、&lt;/span&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700;"&gt;MIPS汇编、&lt;/span&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700;"&gt;Mars、&lt;/span&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700;"&gt;Logisim等实验基础知识和工具学习&lt;/span&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验预习指导</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/903/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/903/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;实验预习指导&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700; text-wrap: wrap;"&gt;数制、&lt;/span&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700;"&gt;MIPS汇编、&lt;/span&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700;"&gt;Mars、&lt;/span&gt;&lt;span style="color: #FF0000; font-family: 微软雅黑; font-size: 19px; font-weight: 700;"&gt;Logisim等实验基础知识和工具学习&lt;/span&gt;&lt;/p&gt;
 
 
 
 
 
 
 &lt;/div&gt;</description></item><item><title>实验题目介绍</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/258/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/258/</guid><description>&lt;p&gt;本次实验共包括两个部分，在Part1中我们将首先完成一个Cache模拟器，从而模拟每条访存指令的命中/缺失情况，在Part2中我们将基于Part1实现的Cache模拟器，针对特定大小的矩阵，给出矩阵转置的优化策略，使得miss（即缺失数）尽可能低。我们只需要根据下发的实验代码，补全文件&lt;code&gt;csim.c&lt;/code&gt;和&lt;code&gt;trans.c&lt;/code&gt;即可。&lt;/p&gt;
&lt;h3 id="part1--cache模拟器实现5分"&gt;Part1 Cache模拟器实现（5分）&lt;/h3&gt;
&lt;p&gt;在本节中，我们将完成一个Cache模拟器，它通过读取memory trace（内存访问记录文件），模拟访问内存的过程，并且给出每条访问记录在Cache中的命中/缺失情况。&lt;strong&gt;本实验只需要补全&lt;code&gt;csim.c&lt;/code&gt;文件中的内容，提交评测也只需提交该文件。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="题目描述"&gt;题目描述&lt;/h4&gt;
&lt;p&gt;我们要求实现的Cache模拟器需要满足的功能详情描述如下。&lt;/p&gt;
&lt;h5 id="读入文件memory-trace格式"&gt;读入文件（memory trace）格式&lt;/h5&gt;
&lt;p&gt;我们实现的Cache模拟器将从文本文件中逐行读取内存访问记录，每一条记录代表了一次内存相关操作。为了评测方便，内存访问记录的格式与valgrind（一个强大的程序内存检测工具，后文会有介绍）的输出格式相同，具体格式如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[space]&amp;lt;operation&amp;gt; &amp;lt;address&amp;gt;,&amp;lt;size&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;operation&amp;gt;&lt;/code&gt;表示操作类型，共分为4类
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;I&lt;/code&gt; 表示取指&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L&lt;/code&gt; 表示取数（Load）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S&lt;/code&gt; 表示存数（Store）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M&lt;/code&gt; 表示修改（可以视为先Load后Store）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[space]&lt;/code&gt;为空格，当&lt;code&gt;&amp;lt;operation&amp;gt;&lt;/code&gt;为除&lt;code&gt;I&lt;/code&gt;类型之外的类型时，会在行首保留一个空格（这一安排是为了与valgrind的格式保持一致）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;address&amp;gt;&lt;/code&gt;为&lt;strong&gt;16进制数&lt;/strong&gt;，表示一个64位地址（注意地址大小可能会超过32位）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;size&amp;gt;&lt;/code&gt;为10进制数，表示存/取的内存大小（单位：字节）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;memory trace示例：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;I 0400d7d4,8
 M 0421c7f0,4
 L 04f6b868,8
 S 7ff0005c8,8
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="cache使用方法"&gt;Cache使用方法&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./csim &lt;span style="color:#f92672"&gt;[&lt;/span&gt;-hv&lt;span style="color:#f92672"&gt;]&lt;/span&gt; -s &amp;lt;s&amp;gt; -E &amp;lt;E&amp;gt; -b &amp;lt;b&amp;gt; -t &amp;lt;tracefile&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt;: 输出帮助信息（&lt;strong&gt;帮助信息选做，不在评测范围内&lt;/strong&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt;: 输出详细trace信息（可以选择是否输出详细信息，输出格式见后文）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s &amp;lt;s&amp;gt;&lt;/code&gt;: set bits （$S=2^s$ 代表组的数量，评测保证 &lt;code&gt;s&lt;/code&gt; 不超过10）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-E &amp;lt;E&amp;gt;&lt;/code&gt;: lines bits （$E$ 代表每组的block个数，即行数/路数，评测保证 &lt;code&gt;E&lt;/code&gt; 不超过 8）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b &amp;lt;b&amp;gt;&lt;/code&gt;: block bits （$B=2^b$ 代表block的大小，单位为字节，评测保证 &lt;code&gt;b&lt;/code&gt; 不超过10）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t &amp;lt;tracefile&amp;gt;&lt;/code&gt;: 内存访问记录文件（memory trace）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们的Cache程序需要完成以下操作：&lt;/p&gt;</description></item><item><title>实验题目介绍</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/977/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/977/</guid><description>&lt;p&gt;本次实验共包括两个部分，在Part1中我们将首先完成一个Cache模拟器，从而模拟每条访存指令的命中/缺失情况，在Part2中我们将基于Part1实现的Cache模拟器，针对特定大小的矩阵，给出矩阵转置的优化策略，使得miss（即缺失数）尽可能低。我们只需要根据下发的实验代码，补全文件&lt;code&gt;csim.c&lt;/code&gt;和&lt;code&gt;trans.c&lt;/code&gt;即可。&lt;/p&gt;
&lt;h3 id="part1--cache模拟器实现5分"&gt;Part1 Cache模拟器实现（5分）&lt;/h3&gt;
&lt;p&gt;在本节中，我们将完成一个Cache模拟器，它通过读取memory trace（内存访问记录文件），模拟访问内存的过程，并且给出每条访问记录在Cache中的命中/缺失情况。&lt;strong&gt;本实验只需要补全&lt;code&gt;csim.c&lt;/code&gt;文件中的内容，提交评测也只需提交该文件。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="题目描述"&gt;题目描述&lt;/h4&gt;
&lt;p&gt;我们要求实现的Cache模拟器需要满足的功能详情描述如下。&lt;/p&gt;
&lt;h5 id="读入文件memory-trace格式"&gt;读入文件（memory trace）格式&lt;/h5&gt;
&lt;p&gt;我们实现的Cache模拟器将从文本文件中逐行读取内存访问记录，每一条记录代表了一次内存相关操作。为了评测方便，内存访问记录的格式与valgrind（一个强大的程序内存检测工具，后文会有介绍）的输出格式相同，具体格式如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[space]&amp;lt;operation&amp;gt; &amp;lt;address&amp;gt;,&amp;lt;size&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;operation&amp;gt;&lt;/code&gt;表示操作类型，共分为4类
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;I&lt;/code&gt; 表示取指&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L&lt;/code&gt; 表示取数（Load）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S&lt;/code&gt; 表示存数（Store）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M&lt;/code&gt; 表示修改（可以视为先Load后Store）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[space]&lt;/code&gt;为空格，当&lt;code&gt;&amp;lt;operation&amp;gt;&lt;/code&gt;为除&lt;code&gt;I&lt;/code&gt;类型之外的类型时，会在行首保留一个空格（这一安排是为了与valgrind的格式保持一致）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;address&amp;gt;&lt;/code&gt;为&lt;strong&gt;16进制数&lt;/strong&gt;，表示一个64位地址（注意地址大小可能会超过32位）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;size&amp;gt;&lt;/code&gt;为10进制数，表示存/取的内存大小（单位：字节）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;memory trace示例：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;I 0400d7d4,8
 M 0421c7f0,4
 L 04f6b868,8
 S 7ff0005c8,8
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="cache使用方法"&gt;Cache使用方法&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./csim &lt;span style="color:#f92672"&gt;[&lt;/span&gt;-hv&lt;span style="color:#f92672"&gt;]&lt;/span&gt; -s &amp;lt;s&amp;gt; -E &amp;lt;E&amp;gt; -b &amp;lt;b&amp;gt; -t &amp;lt;tracefile&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt;: 输出帮助信息（&lt;strong&gt;帮助信息选做，不在评测范围内&lt;/strong&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt;: 输出详细trace信息（可以选择是否输出详细信息，输出格式见后文）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s &amp;lt;s&amp;gt;&lt;/code&gt;: set bits （$S=2^s$ 代表组的数量，评测保证 &lt;code&gt;s&lt;/code&gt; 不超过10）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-E &amp;lt;E&amp;gt;&lt;/code&gt;: lines bits （$E$ 代表每组的block个数，即行数/路数，评测保证 &lt;code&gt;E&lt;/code&gt; 不超过 8）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b &amp;lt;b&amp;gt;&lt;/code&gt;: block bits （$B=2^b$ 代表block的大小，单位为字节，评测保证 &lt;code&gt;b&lt;/code&gt; 不超过10）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t &amp;lt;tracefile&amp;gt;&lt;/code&gt;: 内存访问记录文件（memory trace）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们的Cache程序需要完成以下操作：&lt;/p&gt;</description></item><item><title>数制基础</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/235/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/235/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;数制基础&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n2" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: 1.6rem; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; word-spacing: 0.05rem; caret-color: rgb(52, 73, 94); color: rgb(52, 73, 94); font-family: Ubuntu, "Source Sans Pro", sans-serif; background-color: rgb(255, 255, 255);'&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;本文的核心内容是向同学们介绍&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box; padding: 0px 1px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;计算机的数制基础&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;。学习本文将有助于你：&lt;/span&gt;&lt;/p&gt;&lt;ul cid="n3" class="ul-list list-paddingleft-2" data-mark="-" mdtype="list" style='box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; padding-left: 30px; position: relative; caret-color: rgb(52, 73, 94); color: rgb(52, 73, 94); font-family: Ubuntu, "Source Sans Pro", sans-serif; text-wrap: wrap; text-size-adjust: auto; background-color: rgb(255, 255, 255);'&gt;&lt;li&gt;&lt;p cid="n5" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: 1.6rem; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space-collapse: preserve; position: relative; word-spacing: 0.05rem;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;理解数制的基本概念，掌握进制之间的转换方法和技巧&lt;/span&gt;&lt;/p&gt;</description></item><item><title>数制基础</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/906/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/906/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;数制基础&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n2" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: 1.6rem; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; word-spacing: 0.05rem; caret-color: rgb(52, 73, 94); color: rgb(52, 73, 94); font-family: Ubuntu, "Source Sans Pro", sans-serif; background-color: rgb(255, 255, 255);'&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;本文的核心内容是向同学们介绍&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box; padding: 0px 1px;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;计算机的数制基础&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;。学习本文将有助于你：&lt;/span&gt;&lt;/p&gt;&lt;ul cid="n3" class="ul-list list-paddingleft-2" data-mark="-" mdtype="list" style='box-sizing: border-box; margin-top: 0.8em; margin-bottom: 0.8em; padding-left: 30px; position: relative; caret-color: rgb(52, 73, 94); color: rgb(52, 73, 94); font-family: Ubuntu, "Source Sans Pro", sans-serif; text-wrap: wrap; text-size-adjust: auto; background-color: rgb(255, 255, 255);'&gt;&lt;li&gt;&lt;p cid="n5" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box; line-height: 1.6rem; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space-collapse: preserve; position: relative; word-spacing: 0.05rem;"&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;理解数制的基本概念，掌握进制之间的转换方法和技巧&lt;/span&gt;&lt;/p&gt;</description></item><item><title>敲门篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/249/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/249/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;敲门篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 体系结构中的寄存器&lt;/span&gt;&lt;/h3&gt;&lt;ul class="list-paddingleft-2"&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 结构体系当中定义了 32 个寄存器&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;通用寄存器标志由 $ 符号开头，通常有两种使用的方式：&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class="list-paddingleft-2" style="list-style-type: square;"&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;直接使用对应的寄存器的名称，例如 $t0、$t1、$sp 等。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;直接使用对应的寄存器的编号，例如 $0、$1、$31 等。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;每个寄存器都有其特定的作用，有相应的规范，如下表所示。&lt;/span&gt;&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;thead&gt;&lt;tr class="firstRow"&gt;&lt;th&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;寄存器编号&lt;/span&gt;&lt;/th&gt;&lt;th&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;助记符&lt;/span&gt;&lt;/th&gt;&lt;th&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用途&lt;/span&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;0&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;zero&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;值总是为 0&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;1&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;at&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;（汇编暂存寄存器）一般由汇编器作为临时寄存器使用。我们编写 MIPS 汇编不使用。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;2 - 3&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;v0 - v1&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于存放表达式的值，或函数的整型、指针型的返回值&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;4 - 7&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;a0 - a3&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于函数传参。其值在函数调用的过程中不会被保存。若函数参数较多，多出来的部分通常会使用栈进行传递。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;8 - 15&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;t0 - t7&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于存放表达式的值的临时寄存器。其值在函数调用的过程中不会被保存。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;16 - 23&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;s0 - s7&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;保存寄存器。这些寄存器中的值在经过函数调用之后不会改变。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;24 - 25&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;t8 - t9&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于存放表达式的值的临时寄存器。其值在函数调用的过程中不会被保存。当调用位置无关函数时，25 号寄存器必须存放被调用函数的地址。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;26 - 27&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;k0 - k1&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;仅被操作系统使用。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;28&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;gp&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;全局指针和内容指针。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;29&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;sp&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;栈指针。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;30&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;fp 或 s8&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;保存寄存器（同 s0 - s7）。也可用作帧指针。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;31&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;ra&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;函数返回地址。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description></item><item><title>敲门篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/916/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/916/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;敲门篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 体系结构中的寄存器&lt;/span&gt;&lt;/h3&gt;&lt;ul class="list-paddingleft-2"&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;MIPS 结构体系当中定义了 32 个寄存器&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;通用寄存器标志由 $ 符号开头，通常有两种使用的方式：&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class="list-paddingleft-2" style="list-style-type: square;"&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;直接使用对应的寄存器的名称，例如 $t0、$t1、$sp 等。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;直接使用对应的寄存器的编号，例如 $0、$1、$31 等。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;每个寄存器都有其特定的作用，有相应的规范，如下表所示。&lt;/span&gt;&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;thead&gt;&lt;tr class="firstRow"&gt;&lt;th&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;寄存器编号&lt;/span&gt;&lt;/th&gt;&lt;th&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;助记符&lt;/span&gt;&lt;/th&gt;&lt;th&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用途&lt;/span&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;0&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;zero&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;值总是为 0&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;1&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;at&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;（汇编暂存寄存器）一般由汇编器作为临时寄存器使用。我们编写 MIPS 汇编不使用。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;2 - 3&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;v0 - v1&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于存放表达式的值，或函数的整型、指针型的返回值&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;4 - 7&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;a0 - a3&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于函数传参。其值在函数调用的过程中不会被保存。若函数参数较多，多出来的部分通常会使用栈进行传递。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;8 - 15&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;t0 - t7&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于存放表达式的值的临时寄存器。其值在函数调用的过程中不会被保存。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;16 - 23&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;s0 - s7&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;保存寄存器。这些寄存器中的值在经过函数调用之后不会改变。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;24 - 25&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;t8 - t9&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;用于存放表达式的值的临时寄存器。其值在函数调用的过程中不会被保存。当调用位置无关函数时，25 号寄存器必须存放被调用函数的地址。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;26 - 27&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;k0 - k1&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;仅被操作系统使用。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;28&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;gp&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;全局指针和内容指针。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;29&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;sp&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;栈指针。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;30&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;fp 或 s8&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;保存寄存器（同 s0 - s7）。也可用作帧指针。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;31&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;ra&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;函数返回地址。&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description></item><item><title>时序逻辑</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/239/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/239/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;时序逻辑&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n46" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif;'&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box;"&gt;理论课大家已经学习了时序电路的基本知识，下面我们结合 Logisim 再帮助大家理解一下时序电路。&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;(说明：时序逻辑理论知识可以参考《数字设计原理与实践第四版》P437 Sequential logic 章节。)&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n47" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif;'&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;和组合逻辑电路不同，时序电路需要实现"记忆"的功能，那么电路里必然存在用于记忆过去状态的部件，如何存储过去的信息呢？首先我们一起看一下这个"小物件"：&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;SR 锁存器&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;</description></item><item><title>时序逻辑</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/910/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/910/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;时序逻辑&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n46" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif;'&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box;"&gt;理论课大家已经学习了时序电路的基本知识，下面我们结合 Logisim 再帮助大家理解一下时序电路。&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;(说明：时序逻辑理论知识可以参考《数字设计原理与实践第四版》P437 Sequential logic 章节。)&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n47" class="md-end-block md-p" mdtype="paragraph" style='box-sizing: border-box; line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, "Segoe UI Emoji", sans-serif;'&gt;&lt;span class="md-plain" md-inline="plain" style="box-sizing: border-box;"&gt;和组合逻辑电路不同，时序电路需要实现"记忆"的功能，那么电路里必然存在用于记忆过去状态的部件，如何存储过去的信息呢？首先我们一起看一下这个"小物件"：&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box;"&gt;&lt;strong style="box-sizing: border-box;"&gt;SR 锁存器&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;</description></item><item><title>替换策略与分块技术</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/257/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/257/</guid><description>&lt;h3 id="cache运行与冲突替换"&gt;Cache运行与冲突替换&lt;/h3&gt;
&lt;h4 id="cache运行流程"&gt;Cache运行流程&lt;/h4&gt;
&lt;p&gt;如下图所示，当我们对一个地址进行访存操作时，我们按照前文所述的地址结构进行匹配。&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/496e9440cd823f88cd898a3e540ae15f.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;首先我们根据地址中的组号（set），查找到Cache中的对应组（图中绿色箭头所指的部分）。之后我们将标记（tag）与Cache中该组所有行的tag进行比较（即图中左部比较的部分）。&lt;/p&gt;
&lt;p&gt;如果Cache中某行的tag能够匹配，则说明Cache中有对应的数据块，即&lt;strong&gt;命中&lt;/strong&gt;（hit）。当命中时，处理器直接对Cache进行对应的访存操作，可以通过地址中的offset，查找Cache存储的block中的offset，从而找到该地址对应的数据信息。&lt;/p&gt;
&lt;p&gt;如果Cache中没有对应的数据块，那么就是&lt;strong&gt;不命中&lt;/strong&gt;（miss）的情况。当不命中时，缓存从主存中取出包含该地址的块，并需要放入缓存中。假如Cache中该地址所属组的所有行均已被占用，那么就需要覆盖一个现有的块，这一过程通常称为&lt;strong&gt;替换/驱逐&lt;/strong&gt;（eviction）。&lt;strong&gt;在本实验中，我们假设当Cache的块被换出时，被换出块中如果发生数据更改则此时写回主存。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里我们就会遇到一个问题，当需要替换时，如何在Cache中选择被替换的块？我们的目的是使得发生替换的情况尽可能少，从理论上来说，我们&lt;strong&gt;应当选择现有块中将来不再使用的块，或者选择现有块中经过最长时间才会使用到的块&lt;/strong&gt;，因为这最大程度上推迟了下一次发生替换的时刻，我们可以证明，如果我们能够预知程序未来将要访问的地址的话，上述的替换策略是最优的，这一策略被称为&lt;strong&gt;最佳置换算法&lt;/strong&gt;（OPT，OPTimal selection）。&lt;/p&gt;
&lt;p&gt;事实上，我们很难达到预知未来的要求，我们的替换选择往往通过已有的命中情况来推算，因此我们介绍以下三种常见的替换算法。&lt;/p&gt;
&lt;h4 id="常见替换算法"&gt;常见替换算法&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;先进先出法&lt;/strong&gt;（FIFO，First-In-First-Out），顾名思义，即选择最早装入的块进行替换。它的实现比较简单，不需要记录各个块的访问情况，比较容易实现，开销小。但是这种算法没有依据访存的局部性原理（最早调入的块有可能是经常访问的块），因此不能提高Cache的命中率。&lt;/p&gt;
&lt;p&gt;FIFO策略的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存的每一块都设定一个计数器，初始时均为0。&lt;/li&gt;
&lt;li&gt;当某块被装入或被替换时该块的计数器清为0，而同组的其它各块的计数器均加1，&lt;/li&gt;
&lt;li&gt;当需要替换时就选择计数值最大的块被替换掉。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最低使用频率法&lt;/strong&gt;（LFU，Least-Frequently Used），即替换出使用频率最低的块，又称最不经常使用算法。&lt;/p&gt;
&lt;p&gt;LFU策略的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存的每一块都设定一个计数器，初始时均为0。&lt;/li&gt;
&lt;li&gt;当某块被装入或被访问时该块的计数器加1。&lt;/li&gt;
&lt;li&gt;当需要替换时就选择计数值最小的块被替换掉，如果计数值相同则替换出装入时间更早的块。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最近最少使用法&lt;/strong&gt;（LRU，Least-Recently Used），含义为替换出近期用的最少的块。它与LFU的区别在于它更加关注各个块在近期的访问情况，即近期的权重会更高。LRU需要随时记录Cache中各块的访问情况，以便确定近期最少使用的块。LRU比较复杂，一般来说我们采用简化的方法，只记录每个块最近一次使用的时间，替换时选择&lt;strong&gt;距上一次使用经过时间最长的块&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;LRU策略的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存的每一块都设置一个计数器，初始时均为0。&lt;/li&gt;
&lt;li&gt;访问命中时，所有块的计数值与命中块的计数值进行比较，如果某块计数值小于命中块的计数值， 则该块的计数值加 1；如果该块的计数值大于命中块的计数值，则数值不变；最后将命中块的计数器清为0。&lt;/li&gt;
&lt;li&gt;访问未命中，需要替换/装入时，则选择计数值最大的块被替换/装入，其计数器清为0，而其它的计数器则加1（除了初始装入之外，计数值是不会出现相等情况的，可以思考一下为什么）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分块技术与实验提示"&gt;分块技术与实验提示&lt;/h3&gt;
&lt;h4 id="分块技术"&gt;分块技术&lt;/h4&gt;
&lt;p&gt;分块技术是一项很有趣的技术，它可以提高循环中的时间局部性。分块的大致思想是将一个程序中的数据结构组织成大的块（在这里，“块”指的是一个应用级的数据组块，而不是我们之前介绍的高速缓存块）。这样构造程序，使得能够将一个块加载到高速缓存中，并在这个块内进行所需的所有读和写，然后丢掉这个块再加载下一个块。&lt;/p&gt;
&lt;p&gt;分块会使得代码更难阅读和理解，由于这个原因，它最适合优化编译器或者频繁执行的库函数。这项技术学习和理解起来还是很有趣的，因为它是一个通用的概念，可以在一些系统上获得极大的性能收益。&lt;/p&gt;
&lt;h4 id="实验提示"&gt;实验提示&lt;/h4&gt;
&lt;p&gt;我们将以 $s=5,E=1,b=5$ 结构的Cache为例，结合大小为 $32\times 32$ 的矩阵，来初步分析在矩阵转置中应用分块等技术可以优化的方面，希望能够启发同学们的思路。我们假设矩阵A和B的地址都是block大小对齐的。&lt;/p&gt;
&lt;p&gt;最常规的转置思路即，遍历A的所有行，将其存放到B的对应列中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;trans&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; M, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; N, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; A[N][M], &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; B[M][N])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i, j;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; N; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (j &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; j &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; M; j&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; B[j][i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; A[i][j];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们来结合Cache的结构分析一下转置过程中产生的缺失（miss）情况。首先block大小 $B=2^b=32$ 字节，即可以存放 $8$ 个int型值；$E = 1$ 为直接映射，即Cache中每组只有一行；$S = 2^s=32$ ，即分为 $32$ 个组，整个Cache可以存放 $32\times 8=256$ 个int型值。对应到矩阵中，我们可以发现，矩阵的前8行就正好能够填满我们的Cache。结合下方矩阵B的示意图，我们可以进行进一步的分析。&lt;/p&gt;</description></item><item><title>替换策略与分块技术</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/976/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/976/</guid><description>&lt;h3 id="cache运行与冲突替换"&gt;Cache运行与冲突替换&lt;/h3&gt;
&lt;h4 id="cache运行流程"&gt;Cache运行流程&lt;/h4&gt;
&lt;p&gt;如下图所示，当我们对一个地址进行访存操作时，我们按照前文所述的地址结构进行匹配。&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/496e9440cd823f88cd898a3e540ae15f.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;首先我们根据地址中的组号（set），查找到Cache中的对应组（图中绿色箭头所指的部分）。之后我们将标记（tag）与Cache中该组所有行的tag进行比较（即图中左部比较的部分）。&lt;/p&gt;
&lt;p&gt;如果Cache中某行的tag能够匹配，则说明Cache中有对应的数据块，即&lt;strong&gt;命中&lt;/strong&gt;（hit）。当命中时，处理器直接对Cache进行对应的访存操作，可以通过地址中的offset，查找Cache存储的block中的offset，从而找到该地址对应的数据信息。&lt;/p&gt;
&lt;p&gt;如果Cache中没有对应的数据块，那么就是&lt;strong&gt;不命中&lt;/strong&gt;（miss）的情况。当不命中时，缓存从主存中取出包含该地址的块，并需要放入缓存中。假如Cache中该地址所属组的所有行均已被占用，那么就需要覆盖一个现有的块，这一过程通常称为&lt;strong&gt;替换/驱逐&lt;/strong&gt;（eviction）。&lt;strong&gt;在本实验中，我们假设当Cache的块被换出时，被换出块中如果发生数据更改则此时写回主存。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里我们就会遇到一个问题，当需要替换时，如何在Cache中选择被替换的块？我们的目的是使得发生替换的情况尽可能少，从理论上来说，我们&lt;strong&gt;应当选择现有块中将来不再使用的块，或者选择现有块中经过最长时间才会使用到的块&lt;/strong&gt;，因为这最大程度上推迟了下一次发生替换的时刻，我们可以证明，如果我们能够预知程序未来将要访问的地址的话，上述的替换策略是最优的，这一策略被称为&lt;strong&gt;最佳置换算法&lt;/strong&gt;（OPT，OPTimal selection）。&lt;/p&gt;
&lt;p&gt;事实上，我们很难达到预知未来的要求，我们的替换选择往往通过已有的命中情况来推算，因此我们介绍以下三种常见的替换算法。&lt;/p&gt;
&lt;h4 id="常见替换算法"&gt;常见替换算法&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;先进先出法&lt;/strong&gt;（FIFO，First-In-First-Out），顾名思义，即选择最早装入的块进行替换。它的实现比较简单，不需要记录各个块的访问情况，比较容易实现，开销小。但是这种算法没有依据访存的局部性原理（最早调入的块有可能是经常访问的块），因此不能提高Cache的命中率。&lt;/p&gt;
&lt;p&gt;FIFO策略的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存的每一块都设定一个计数器，初始时均为0。&lt;/li&gt;
&lt;li&gt;当某块被装入或被替换时该块的计数器清为0，而同组的其它各块的计数器均加1，&lt;/li&gt;
&lt;li&gt;当需要替换时就选择计数值最大的块被替换掉。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最低使用频率法&lt;/strong&gt;（LFU，Least-Frequently Used），即替换出使用频率最低的块，又称最不经常使用算法。&lt;/p&gt;
&lt;p&gt;LFU策略的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存的每一块都设定一个计数器，初始时均为0。&lt;/li&gt;
&lt;li&gt;当某块被装入或被访问时该块的计数器加1。&lt;/li&gt;
&lt;li&gt;当需要替换时就选择计数值最小的块被替换掉，如果计数值相同则替换出装入时间更早的块。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最近最少使用法&lt;/strong&gt;（LRU，Least-Recently Used），含义为替换出近期用的最少的块。它与LFU的区别在于它更加关注各个块在近期的访问情况，即近期的权重会更高。LRU需要随时记录Cache中各块的访问情况，以便确定近期最少使用的块。LRU比较复杂，一般来说我们采用简化的方法，只记录每个块最近一次使用的时间，替换时选择&lt;strong&gt;距上一次使用经过时间最长的块&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;LRU策略的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存的每一块都设置一个计数器，初始时均为0。&lt;/li&gt;
&lt;li&gt;访问命中时，所有块的计数值与命中块的计数值进行比较，如果某块计数值小于命中块的计数值， 则该块的计数值加 1；如果该块的计数值大于命中块的计数值，则数值不变；最后将命中块的计数器清为0。&lt;/li&gt;
&lt;li&gt;访问未命中，需要替换/装入时，则选择计数值最大的块被替换/装入，其计数器清为0，而其它的计数器则加1（除了初始装入之外，计数值是不会出现相等情况的，可以思考一下为什么）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分块技术与实验提示"&gt;分块技术与实验提示&lt;/h3&gt;
&lt;h4 id="分块技术"&gt;分块技术&lt;/h4&gt;
&lt;p&gt;分块技术是一项很有趣的技术，它可以提高循环中的时间局部性。分块的大致思想是将一个程序中的数据结构组织成大的块（在这里，“块”指的是一个应用级的数据组块，而不是我们之前介绍的高速缓存块）。这样构造程序，使得能够将一个块加载到高速缓存中，并在这个块内进行所需的所有读和写，然后丢掉这个块再加载下一个块。&lt;/p&gt;
&lt;p&gt;分块会使得代码更难阅读和理解，由于这个原因，它最适合优化编译器或者频繁执行的库函数。这项技术学习和理解起来还是很有趣的，因为它是一个通用的概念，可以在一些系统上获得极大的性能收益。&lt;/p&gt;
&lt;h4 id="实验提示"&gt;实验提示&lt;/h4&gt;
&lt;p&gt;我们将以 $s=5,E=1,b=5$ 结构的Cache为例，结合大小为 $32\times 32$ 的矩阵，来初步分析在矩阵转置中应用分块等技术可以优化的方面，希望能够启发同学们的思路。我们假设矩阵A和B的地址都是block大小对齐的。&lt;/p&gt;
&lt;p&gt;最常规的转置思路即，遍历A的所有行，将其存放到B的对应列中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;trans&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; M, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; N, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; A[N][M], &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; B[M][N])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i, j;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; N; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (j &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; j &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; M; j&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; B[j][i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; A[i][j];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们来结合Cache的结构分析一下转置过程中产生的缺失（miss）情况。首先block大小 $B=2^b=32$ 字节，即可以存放 $8$ 个int型值；$E = 1$ 为直接映射，即Cache中每组只有一行；$S = 2^s=32$ ，即分为 $32$ 个组，整个Cache可以存放 $32\times 8=256$ 个int型值。对应到矩阵中，我们可以发现，矩阵的前8行就正好能够填满我们的Cache。结合下方矩阵B的示意图，我们可以进行进一步的分析。&lt;/p&gt;</description></item><item><title>有限状态机</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/240/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/240/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;有限状态机&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n62" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;有限状态机,也称为FSM(Finite&lt;/span&gt; &lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box"&gt;StateMachine)，其在任意时刻都处于有限状态集合中的某一状态。当其获得一个输入字符时，将从当前状态转换到另一个状态，或者仍然保持在当前状态。任何一个FSM都可以用状态转换图来描述，图中的节点表示FSM中的一状态，有向加权边表示输入字符时状态的变化。&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box"&gt;(说明：有限状态机理论知识可以参考《数字设计原理与实践第四版》P452 clocked synchronous state-machine analysis 部分。)&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n63" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;而有限状态机又分为Moore型有限状态机和Mealy型有限状态机。简而言之，&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box"&gt;Moore型有限状态机输出仅仅和当前状态有关；Mealy 型状态机输出和当前状态以及输入信号都有关。但是二者的下一状态都是仅和当前状态以及输入信号有关，它们之间的关系是组合逻辑关系。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n64" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;接下来我们学习一下如何用 Logisim 实现有限状态机。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>有限状态机</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/911/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/911/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;有限状态机&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n62" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;有限状态机,也称为FSM(Finite&lt;/span&gt; &lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box"&gt;StateMachine)，其在任意时刻都处于有限状态集合中的某一状态。当其获得一个输入字符时，将从当前状态转换到另一个状态，或者仍然保持在当前状态。任何一个FSM都可以用状态转换图来描述，图中的节点表示FSM中的一状态，有向加权边表示输入字符时状态的变化。&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box"&gt;(说明：有限状态机理论知识可以参考《数字设计原理与实践第四版》P452 clocked synchronous state-machine analysis 部分。)&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n63" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;而有限状态机又分为Moore型有限状态机和Mealy型有限状态机。简而言之，&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box"&gt;Moore型有限状态机输出仅仅和当前状态有关；Mealy 型状态机输出和当前状态以及输入信号都有关。但是二者的下一状态都是仅和当前状态以及输入信号有关，它们之间的关系是组合逻辑关系。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p cid="n64" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;接下来我们学习一下如何用 Logisim 实现有限状态机。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>组合逻辑</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/238/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/238/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;组合逻辑&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n20" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box"&gt;基本的门电路知识掌握以后，接下来我们介绍一下数字电路的基本知识：组合逻辑和时序逻辑。&lt;/span&gt;&lt;/p&gt;&lt;p cid="n21" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;数字电路根据逻辑功能的不同特点，可以分成两大类，一类叫组合逻辑电路（简称组合电路），另一类叫做时序逻辑电路（简称时序电路）。他们有什么区别呢，其实很简单：大家都知道，我们做的每个小电路，都可以抽象成一块封装好的，具有一定功能的电路板，它有输入端、电路板主体（就是内部结构）和输出端。电路内部结构和输入信号共同决定输出信号。&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box"&gt;组合逻辑电路的输出仅仅取决于当前输入；时序逻辑电路的输出取决于当前的输入和电路原来的状态，或者可以说：时序逻辑电路的输出，不仅与当前输入有关，也与过去的输入有关。&lt;/strong&gt;&lt;/span&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;时序逻辑是有记忆的电路板，组合逻辑是没有记忆的电路板。&lt;/span&gt;&lt;/p&gt;&lt;p cid="n21" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;&lt;img alt="2.png" src="../images/166584582937301927257.png" title="1665845829373019272.png"/&gt;&lt;/span&gt;&lt;/p&gt;</description></item><item><title>组合逻辑</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/909/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/909/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;组合逻辑&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p cid="n20" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span class="md-plain md-expand" md-inline="plain" style="box-sizing: border-box"&gt;基本的门电路知识掌握以后，接下来我们介绍一下数字电路的基本知识：组合逻辑和时序逻辑。&lt;/span&gt;&lt;/p&gt;&lt;p cid="n21" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;数字电路根据逻辑功能的不同特点，可以分成两大类，一类叫组合逻辑电路（简称组合电路），另一类叫做时序逻辑电路（简称时序电路）。他们有什么区别呢，其实很简单：大家都知道，我们做的每个小电路，都可以抽象成一块封装好的，具有一定功能的电路板，它有输入端、电路板主体（就是内部结构）和输出端。电路内部结构和输入信号共同决定输出信号。&lt;/span&gt;&lt;span class="md-pair-s" md-inline="strong" style="box-sizing: border-box"&gt;&lt;strong style="box-sizing: border-box"&gt;组合逻辑电路的输出仅仅取决于当前输入；时序逻辑电路的输出取决于当前的输入和电路原来的状态，或者可以说：时序逻辑电路的输出，不仅与当前输入有关，也与过去的输入有关。&lt;/strong&gt;&lt;/span&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;时序逻辑是有记忆的电路板，组合逻辑是没有记忆的电路板。&lt;/span&gt;&lt;/p&gt;&lt;p cid="n21" class="md-end-block md-p" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;position: relative;color: rgb(51, 51, 51);font-family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, 'Segoe UI Emoji', sans-serif"&gt;&lt;span md-inline="plain" style="box-sizing: border-box"&gt;&lt;img alt="2.png" src="../images/0c0afb69598ddc37d90a721080b6e843.png" title="1665845829373019272.png"/&gt;&lt;/span&gt;&lt;/p&gt;</description></item><item><title>进阶篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/252/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/252/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;进阶篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;函数&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;虽然前面有宏定义，但是 MIPS 本身还是有函数的使用的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;宏定义和函数的关系就像是 C 语言当中 &lt;/span&gt;&lt;code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;#define&lt;/span&gt;&lt;/code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; 关键字 和 函数 的关系一样。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;首先，我们来学习 jal（jump and link）指令。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;jal 指令的意思是跳转到对应标签的位置，并将当前执行的指令位置存储在 $ra 寄存器中。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;前面说过 $a0 - $a3 寄存器的作用是函数传参，意味着如果在 jal 指令调用之前，往 $a0 - $a3 寄存器当中存放了数据，那么 jal 指令调用之后，这几个寄存器的值是可以直接拿出来用的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;既然 $ra 寄存器当中存放了调用之前的执行的位置，当函数调用结束后可使用 jr（jump register）指令：&lt;/span&gt;&lt;code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;jr $ra&lt;/span&gt;&lt;/code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; ，返回（return）这个函数，&lt;strong&gt;函数的返回值存储在 $v0 和 $v1 寄存器中&lt;/strong&gt;。（MIPS 甚至可以有两个返回值）&lt;/span&gt;&lt;/p&gt;</description></item><item><title>进阶篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/920/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/920/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;进阶篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;函数&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;虽然前面有宏定义，但是 MIPS 本身还是有函数的使用的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;宏定义和函数的关系就像是 C 语言当中 &lt;/span&gt;&lt;code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;#define&lt;/span&gt;&lt;/code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; 关键字 和 函数 的关系一样。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;首先，我们来学习 jal（jump and link）指令。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;jal 指令的意思是跳转到对应标签的位置，并将当前执行的指令位置存储在 $ra 寄存器中。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;前面说过 $a0 - $a3 寄存器的作用是函数传参，意味着如果在 jal 指令调用之前，往 $a0 - $a3 寄存器当中存放了数据，那么 jal 指令调用之后，这几个寄存器的值是可以直接拿出来用的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;既然 $ra 寄存器当中存放了调用之前的执行的位置，当函数调用结束后可使用 jr（jump register）指令：&lt;/span&gt;&lt;code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;jr $ra&lt;/span&gt;&lt;/code&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; ，返回（return）这个函数，&lt;strong&gt;函数的返回值存储在 $v0 和 $v1 寄存器中&lt;/strong&gt;。（MIPS 甚至可以有两个返回值）&lt;/span&gt;&lt;/p&gt;</description></item><item><title>高级篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/254/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/254/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;高级篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;前面我们已经学习了 MIPS 汇编的基本使用。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;下面我们在此基础上回顾一下 MIPS 汇编，同时讲一些高级一点的用法。&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;宏定义&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;有的同学可能会说，这个输入输出每次都要写好几条指令才能做到，但是每次写起来都是一样的，有没有更方便的方法去完成这件事呢？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;当然有，我们隆重向大家介绍宏定义。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;宏定义需要使用 .macro 和 .end_macro 进行包裹。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;看下面的例子：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; .macro RI(%i)&lt;br/&gt;     li $v0, 5&lt;br&gt;     syscall&lt;br/&gt;     move %i, $v0&lt;br/&gt; .end_macro&lt;br/&gt;&lt;/br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;首先阅读一下中间三行 MIPS 代码：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;$v0 寄存器的值设置成 5，然后 syscall 系统调用，这个时候程序会进行读入整数的操作。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>高级篇</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/919/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/919/</guid><description>&lt;div class="blog-post"&gt;
 
 &lt;h3 class="blog-post-title"&gt;高级篇&lt;/h3&gt;
 
 
 
 
 
 
 
 &lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;前面我们已经学习了 MIPS 汇编的基本使用。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;下面我们在此基础上回顾一下 MIPS 汇编，同时讲一些高级一点的用法。&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;宏定义&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;有的同学可能会说，这个输入输出每次都要写好几条指令才能做到，但是每次写起来都是一样的，有没有更方便的方法去完成这件事呢？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;当然有，我们隆重向大家介绍宏定义。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;宏定义需要使用 .macro 和 .end_macro 进行包裹。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;看下面的例子：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt; .macro RI(%i)&lt;br/&gt;     li $v0, 5&lt;br&gt;     syscall&lt;br/&gt;     move %i, $v0&lt;br/&gt; .end_macro&lt;br/&gt;&lt;/br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;首先阅读一下中间三行 MIPS 代码：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Menlo, Monaco, Consolas, monospace;"&gt;$v0 寄存器的值设置成 5，然后 syscall 系统调用，这个时候程序会进行读入整数的操作。&lt;/span&gt;&lt;/p&gt;</description></item><item><title>高速缓存简介</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2023/256/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2023/256/</guid><description>&lt;p&gt;考虑到实验内容的发布早于理论课，因此补充了本章理论介绍的内容，为大家提供一些理论上的参考。&lt;/p&gt;
&lt;p&gt;如果阅读完本章仍然有所困惑，可以参考课程教材CSAPP（深入理解计算机系统）的6.2-6.4节。&lt;/p&gt;
&lt;h3 id="缓存与局部性原理"&gt;缓存与局部性原理&lt;/h3&gt;
&lt;h4 id="存储器层次结构中的缓存"&gt;存储器层次结构中的缓存&lt;/h4&gt;
&lt;p&gt;早期计算机系统的存储器层次结构只有三层：CPU寄存器、DRAM主存储器和磁盘存储。不过，由于CPU和主存之间逐渐增大的性能差距，系统设计者被迫在CPU寄存器文件和主存之间插入了一个小的SRAM高速缓存存储器，称为L1高速缓存。SRAM的价格比主存贵，但因其容量远小于主存，因此能很好地解决速度和成本的矛盾。L1高速缓存的访问速度几乎和寄存器一样快，典型的是2~4个时钟周期。&lt;/p&gt;
&lt;p&gt;随着CPU和主存之间的性能差距不断增大，系统设计者在L1高速缓存和主存之间又插入了一个更大的高速缓存，称为L2高速缓存，有些现代系统还包括有一个更大的高速缓存，称为L3高速缓存。虽然安排上有很多的变化，但是通用的原则还是一样的，&lt;strong&gt;在本实验中，我们可以视为CPU和主存之间只有一个L1高速缓存&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id="局部性原理"&gt;局部性原理&lt;/h4&gt;
&lt;p&gt;局部性原理是缓存设计所依托的基本思想，大量典型程序的运行情况分析结果表明，无论是存取指令或存取数据所访问的存储单元都趋于聚集在一个较小的连续存储区域中。&lt;/p&gt;
&lt;p&gt;局部性原理通常有两种不同的形式：&lt;strong&gt;时间局部性&lt;/strong&gt;和&lt;strong&gt;空间局部性&lt;/strong&gt;。时间局部性可以概括为：刚被访问的存储单元可能不久又将被访问。空间局部性则可以概括为：刚被访问过的存储单元的邻近单位可能不久会被访问。&lt;/p&gt;
&lt;p&gt;比如我们访问一个数组的某个内存单元，那么我们很可能紧接着就要访问它相邻的下一个内存单元，或者我们不久之后还要再次访问这一单元，局部性原理正是表达了这样的思想。而进一步地，如果我们能在访问这一内存单元的时候，将它还有与它相邻的一小部分内存单元加入存取速度更高的缓存中，那么在后续访问的过程中，就能够直接到缓存中访问，从而显著加快程序运行的速度，这正体现了缓存设计的基本思想。&lt;/p&gt;
&lt;h3 id="通用高速缓存结构"&gt;通用高速缓存结构&lt;/h3&gt;
&lt;p&gt;基于以上的介绍，我们对高速缓存（Cache）可以建立起一些抽象的认识：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相对大而慢的主存而言，Cache应当是小而快的。&lt;/li&gt;
&lt;li&gt;对于程序中对某个地址的访问，Cache应当能够获取一个对应的局部块。&lt;/li&gt;
&lt;li&gt;当程序中对相邻地址继续访问时，可以通过访问Cache来实现，不必再次访问主存。&lt;/li&gt;
&lt;li&gt;Cache应当在程序经常访问的位置发生变化时，腾出空间给新的局部块。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面我们来详细的介绍通用的Cache的结构：&lt;/p&gt;
&lt;p&gt;考虑主存地址为 $n$ 位的计算机系统，主存大小即 $2^n$ 字节，我们取这 $n$ 位中的低 $b$ 位，以 $B=2^b$ 作为一个块的大小，从而将地址空间划分为 $2^{n-b}$ 个&lt;strong&gt;块&lt;/strong&gt;（block）。对应的，地址的低 $b$ 位表示一个字节相对于本块内的位置，我们称为&lt;strong&gt;块内偏移&lt;/strong&gt;（offset），地址的高 $n-b$ 位即表示&lt;strong&gt;块号&lt;/strong&gt;（block number）。其地址格式即如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/d171e20138dc70803a464c589b6050c3.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我们可以理解为，Cache在从主存中存取数据时，就是以块为单位进行操作的。相应的，Cache在数据组织的过程中，自然也要以块为基本单元，在存储一个块的同时，Cache也要存储一些与此块相对应的信息，我们将Cache中这样包含了一个块和其相关信息的结构称为&lt;strong&gt;行&lt;/strong&gt;（line）。&lt;/p&gt;
&lt;p&gt;主存中有诸多的块，而Cache的大小尽管远小于主存，仍然能存放相当数量的行，我们希望解决从主存的块到Cache的行的映射关系，这里要引入&lt;strong&gt;组&lt;/strong&gt;（set）的概念。我们将主存的所有块分为 $S=2^s$ 组，同时我们将Cache也作对应分组，我们使得&lt;strong&gt;主存中同组的那些块仅能映射到Cache中对应组的那些行中&lt;/strong&gt;。这样我们在拿到一个地址之后，首先分析它所在的分组，再在Cache中对应的分组中查询有没有对应的行，从而降低在Cache中查询的成本。而当Cache同组的所有行都填满之后，我们也只会腾出该组中的行来存放新的数据块，不会影响其他组。&lt;/p&gt;
&lt;p&gt;我们希望分组之后&lt;strong&gt;相邻的块能被分到不同的组&lt;/strong&gt;（由于局部性原理，相邻的块也有可能同时需要访问，我们不希望把它们分到同一组来相互挤占有限的Cache资源），因此我们将块号（即内存地址的高 $n-b$ 位）的低 $s$ 位作为组号。而由于主存的分组已经和Cache的分组建立起对应关系，我们在Cache中只需要地址的高 $n-s-b$ 位作为&lt;strong&gt;标记&lt;/strong&gt;（tag），就可以唯一地识别出该组中是否有哪一行存放了我们的想要的主存块。这样划分后的地址格式如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/6dc7c08c6b16cfafba03277d55a0ccdd.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;相应的Cache结构如下图所示：首先Cache包含 $S=2^s$ 个高速缓存组（set）；每个组包含 $E$ 个高速缓存行（line）；每个行由三部分组成，一个 $B=2^b$ 字节的数据块（block），一个有效位（valid bit）指明这个行保存的信息是否有意义，还有 $t=n-(b+s)$ 个标记位（tag）来唯一地识别组内的某一行。&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/36792408a2773c47dc47af0ccf35e355.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这样结构的Cache，我们称之为&lt;strong&gt;组相联&lt;/strong&gt;的。&lt;/p&gt;
&lt;p&gt;当 $s=0$ ，即组的数量退化为只有一组时， 主存中的任意块都可以映射到Cache中的任意行，这种情况下的Cache我们称为是&lt;strong&gt;全相联&lt;/strong&gt;的。而当 $E = 1$，即Cache中每组的行数退化为只有一行时，这种情况主存中同组的若干块都只能映射到Cache中的特定一行，我们将其称为&lt;strong&gt;直接映射&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>高速缓存简介</title><link>https://awesome-buaa-cs.github.io/fch-tutorial/2024/975/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://awesome-buaa-cs.github.io/fch-tutorial/2024/975/</guid><description>&lt;p&gt;考虑到实验内容的发布早于理论课，因此补充了本章理论介绍的内容，为大家提供一些理论上的参考。&lt;/p&gt;
&lt;p&gt;如果阅读完本章仍然有所困惑，可以参考课程教材CSAPP（深入理解计算机系统）的6.2-6.4节。&lt;/p&gt;
&lt;h3 id="缓存与局部性原理"&gt;缓存与局部性原理&lt;/h3&gt;
&lt;h4 id="存储器层次结构中的缓存"&gt;存储器层次结构中的缓存&lt;/h4&gt;
&lt;p&gt;早期计算机系统的存储器层次结构只有三层：CPU寄存器、DRAM主存储器和磁盘存储。不过，由于CPU和主存之间逐渐增大的性能差距，系统设计者被迫在CPU寄存器文件和主存之间插入了一个小的SRAM高速缓存存储器，称为L1高速缓存。SRAM的价格比主存贵，但因其容量远小于主存，因此能很好地解决速度和成本的矛盾。L1高速缓存的访问速度几乎和寄存器一样快，典型的是2~4个时钟周期。&lt;/p&gt;
&lt;p&gt;随着CPU和主存之间的性能差距不断增大，系统设计者在L1高速缓存和主存之间又插入了一个更大的高速缓存，称为L2高速缓存，有些现代系统还包括有一个更大的高速缓存，称为L3高速缓存。虽然安排上有很多的变化，但是通用的原则还是一样的，&lt;strong&gt;在本实验中，我们可以视为CPU和主存之间只有一个L1高速缓存&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id="局部性原理"&gt;局部性原理&lt;/h4&gt;
&lt;p&gt;局部性原理是缓存设计所依托的基本思想，大量典型程序的运行情况分析结果表明，无论是存取指令或存取数据所访问的存储单元都趋于聚集在一个较小的连续存储区域中。&lt;/p&gt;
&lt;p&gt;局部性原理通常有两种不同的形式：&lt;strong&gt;时间局部性&lt;/strong&gt;和&lt;strong&gt;空间局部性&lt;/strong&gt;。时间局部性可以概括为：刚被访问的存储单元可能不久又将被访问。空间局部性则可以概括为：刚被访问过的存储单元的邻近单位可能不久会被访问。&lt;/p&gt;
&lt;p&gt;比如我们访问一个数组的某个内存单元，那么我们很可能紧接着就要访问它相邻的下一个内存单元，或者我们不久之后还要再次访问这一单元，局部性原理正是表达了这样的思想。而进一步地，如果我们能在访问这一内存单元的时候，将它还有与它相邻的一小部分内存单元加入存取速度更高的缓存中，那么在后续访问的过程中，就能够直接到缓存中访问，从而显著加快程序运行的速度，这正体现了缓存设计的基本思想。&lt;/p&gt;
&lt;h3 id="通用高速缓存结构"&gt;通用高速缓存结构&lt;/h3&gt;
&lt;p&gt;基于以上的介绍，我们对高速缓存（Cache）可以建立起一些抽象的认识：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相对大而慢的主存而言，Cache应当是小而快的。&lt;/li&gt;
&lt;li&gt;对于程序中对某个地址的访问，Cache应当能够获取一个对应的局部块。&lt;/li&gt;
&lt;li&gt;当程序中对相邻地址继续访问时，可以通过访问Cache来实现，不必再次访问主存。&lt;/li&gt;
&lt;li&gt;Cache应当在程序经常访问的位置发生变化时，腾出空间给新的局部块。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面我们来详细的介绍通用的Cache的结构：&lt;/p&gt;
&lt;p&gt;考虑主存地址为 $n$ 位的计算机系统，主存大小即 $2^n$ 字节，我们取这 $n$ 位中的低 $b$ 位，以 $B=2^b$ 作为一个块的大小，从而将地址空间划分为 $2^{n-b}$ 个&lt;strong&gt;块&lt;/strong&gt;（block）。对应的，地址的低 $b$ 位表示一个字节相对于本块内的位置，我们称为&lt;strong&gt;块内偏移&lt;/strong&gt;（offset），地址的高 $n-b$ 位即表示&lt;strong&gt;块号&lt;/strong&gt;（block number）。其地址格式即如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/d171e20138dc70803a464c589b6050c3.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我们可以理解为，Cache在从主存中存取数据时，就是以块为单位进行操作的。相应的，Cache在数据组织的过程中，自然也要以块为基本单元，在存储一个块的同时，Cache也要存储一些与此块相对应的信息，我们将Cache中这样包含了一个块和其相关信息的结构称为&lt;strong&gt;行&lt;/strong&gt;（line）。&lt;/p&gt;
&lt;p&gt;主存中有诸多的块，而Cache的大小尽管远小于主存，仍然能存放相当数量的行，我们希望解决从主存的块到Cache的行的映射关系，这里要引入&lt;strong&gt;组&lt;/strong&gt;（set）的概念。我们将主存的所有块分为 $S=2^s$ 组，同时我们将Cache也作对应分组，我们使得&lt;strong&gt;主存中同组的那些块仅能映射到Cache中对应组的那些行中&lt;/strong&gt;。这样我们在拿到一个地址之后，首先分析它所在的分组，再在Cache中对应的分组中查询有没有对应的行，从而降低在Cache中查询的成本。而当Cache同组的所有行都填满之后，我们也只会腾出该组中的行来存放新的数据块，不会影响其他组。&lt;/p&gt;
&lt;p&gt;我们希望分组之后&lt;strong&gt;相邻的块能被分到不同的组&lt;/strong&gt;（由于局部性原理，相邻的块也有可能同时需要访问，我们不希望把它们分到同一组来相互挤占有限的Cache资源），因此我们将块号（即内存地址的高 $n-b$ 位）的低 $s$ 位作为组号。而由于主存的分组已经和Cache的分组建立起对应关系，我们在Cache中只需要地址的高 $n-s-b$ 位作为&lt;strong&gt;标记&lt;/strong&gt;（tag），就可以唯一地识别出该组中是否有哪一行存放了我们的想要的主存块。这样划分后的地址格式如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/6dc7c08c6b16cfafba03277d55a0ccdd.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;相应的Cache结构如下图所示：首先Cache包含 $S=2^s$ 个高速缓存组（set）；每个组包含 $E$ 个高速缓存行（line）；每个行由三部分组成，一个 $B=2^b$ 字节的数据块（block），一个有效位（valid bit）指明这个行保存的信息是否有意义，还有 $t=n-(b+s)$ 个标记位（tag）来唯一地识别组内的某一行。&lt;/p&gt;
&lt;p&gt;&lt;img src="../images/36792408a2773c47dc47af0ccf35e355.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这样结构的Cache，我们称之为&lt;strong&gt;组相联&lt;/strong&gt;的。&lt;/p&gt;
&lt;p&gt;当 $s=0$ ，即组的数量退化为只有一组时， 主存中的任意块都可以映射到Cache中的任意行，这种情况下的Cache我们称为是&lt;strong&gt;全相联&lt;/strong&gt;的。而当 $E = 1$，即Cache中每组的行数退化为只有一行时，这种情况主存中同组的若干块都只能映射到Cache中的特定一行，我们将其称为&lt;strong&gt;直接映射&lt;/strong&gt;。&lt;/p&gt;</description></item></channel></rss>