26考研 | 计算机组成原理 | 关于五段式指令流水线译码阶段取操作数可以去主存中拿吗
关于五段式指令流水线译码阶段取操作数可以去主存中拿吗1.可以从主存拿吗答:在标准的五段流水线中,“译码/读寄存器”阶段的操作数来源特指从寄存器文件(Register File)中读取。 它不会从主存中取操作数。 下面是详细的解释: 译码阶段(ID)的主要任务 译码阶段通常完成以下两件核心工作: 指令译码: 解析指令的操作码,确定指令的类型(是加法、加载还是存储等)和所需的操作数。 读寄存器: 根据指令中指定的寄存器地址(例如 add R4, R5, R3中的 R5 和 R3),从寄存器文件中读出这两个寄存器的当前值。 所以,图片中表格将这一阶段标注为“译码/读寄存器”是非常准确的,明确了操作数的来源是寄存器。 操作数的不同来源 一条指令的操作数可以来自三个地方,对应不同的流水线阶段: 操作数来源 对应的流水线阶段 指令示例 解释 寄存器 译码阶段 add R1, R2, R3 操作数 R2 和 R3 的值在 ID 阶段从寄存器文件读出。 立即数 译码阶段 addi R1, R2, #10 操作数一个是寄存器...
26考研 | 计算机组成原理 | 单周期CPU和多周期CPU的总线结构的适用情况
单周期CPU和多周期CPU的总线结构的适用情况在一条指令的执行过程中,单周期CPU的每个控制信号保持不变,每个部件只能使用一次。多周期CPU的控制信号可能发生改变,同一个部件可以使用多次 关于这句话的具体解释 特性 单周期CPU 多周期CPU 指令执行方式 所有操作在一个长时钟周期内完成 指令被分解为多个阶段,每个阶段占用一个较短的时钟周期 控制信号 恒定不变:周期开始时生成,整个周期内保持稳定 动态变化:每个周期(阶段)根据当前步骤重新生成一组信号 部件使用 一次使用:每个功能部件(如ALU、存储器)在一个指令周期内通常只工作一次 多次复用:同一部件(如ALU)可在不同阶段被同一条或不同指令多次使用 指令间关系 串行执行:下一条指令必须等当前指令完全执行完毕后才开始 串行执行:下一条指令仍需等待当前指令的所有步骤完成后方可开始 使用什么总线结构 不能使用单总线结构,只能使用多总线或者专用数据通路结构 单、多、专用都可以 ...
26考研 | 计算机组成原理 | 计算机组成原理关于指令流水线数据冒险解决方案的困惑以及梳理
计算机组成原理关于指令流水线数据冒险解决方案的困惑以及梳理笔者是在做这道题的时候产生的困惑以及解决 附上答案 1.阻塞方式把I3指令的ID阶段阻塞到时钟6去执行。因为ID阶段是读寄存器的,必须要在I2的WB阶段结束之后,也就是时钟6,一共阻塞3个时钟 2.数据通路方式解决这个问题我的困惑: 假如A与B指令有数据冲突,数据通路的方式解决的话,那是不是只要在A执行阶段我把结果算出来之后,存到A指令执行阶段的锁存器,然后B指令的执行阶段就可以拿走直接用?还是说B指令的译码阶段取操作数这个操作要等到A指令的EX阶段执行完以后,然后数据通路把A指令的EX段锁存器的内容给到B指令,B指令才去进行EX阶段? 答案是在A指令的执行(EX)阶段结束后,结果被存入EX/MEM流水线锁存器。随后,在B指令的EX阶段开始时,转发逻辑可以直接从这个锁存器中取出数据供B指令使用。 简单来说就是:B指令的译码解决还是会拿到错误的值,但是数据通路会在B指令进去EX阶段之前把错误的值用正确的值给覆盖掉。而其实ID阶段拿到错误的值也没事,毕竟也没执行。 转发机制(Data...
操作系统 | 进程的内存映像
操作系统 | 进程的内存映像 不同于存放在硬盘上的可执行程序文件,当一个程序调入内存运行时,就构成了进程的内存映像。一个进程的内存映像一般有几个要素: 代码段:即程序的二进制代码,代码段是只读的,可以被多个进程共享。 数据段:即程序运行时加工处理的对象,包括全局变量和静态变量。 进程控制块(PCB):存放在系统区。操作系统通过PCB来控制和管理进程。 堆:用来存放动态分配的变量。通过调用malloc...
I/O系统 - scanf执行过程
I/O系统 - scanf执行过程源自26考研王道基础课及强化课(含笔者自己总结部分) 在讨论之前,先补充两个概念:内核缓冲区(就是处于内核空间的缓冲区)和与之对应的用户缓冲区。 在scanf函数执行的第一阶段,就申请了用户缓冲区buf,由于buf位于用户空间中,而接下来需要在内核空间中运行,这两个空间是相互独立的。内核空间用来存放操作系统的代码和数据,是供所有进程共享的。 系统调用函数运行在内核态,因此要先把I/O端口中的数据复制到内核空间中,在系统调用返回前,再将数据从内核空间复制到用户空间。 程序调用“scanf("%c",&d)”时,尝试用键盘输入对变量d进行赋值。scanf()会关联一个用户缓冲区buf,这个缓冲区是C语言函数库在用户空间中管理的。 scanf()的第一阶段的工作是在C语言函数库中完成的: 1.检查与scanf函数关联的用户缓冲区buf,若缓冲区中已有数据,则直接读取。若缓冲区为空,则触发系统调用read,以从内核缓冲区中读取数据。 2.执行系统调用read,read...
硬盘制为启动盘的过程 && 操作系统的引导过程
硬盘制为启动盘的过程 && 操作系统的引导过程1.硬盘制为启动盘的过程大致流程: 0.简略版1.磁盘的物理格式化 用于划分磁道和扇区,为存储数据准备物理空间 2.磁盘分区 将整个硬盘划分为多个独立的逻辑区域(如C盘、D盘),便于数据管理。此过程会创建主引导记录(MBR),其中包含了分区信息。 3.磁盘的逻辑格式化 在每个分区内创建文件系统(如NTFS、FAT32、EXT4),初始化引导块、超级块、根目录等管理结构。这样,操作系统才能识别和读写该分区。 4.安装操作系统 将操作系统(如Windows、Linux)的核心文件复制到活动分区(通常是C盘)。 安装引导程序(如Windows的Boot...
Day136 | 灵神 | 回溯算法 | 子集型 串联字符串的最大长度
Day136 | 灵神 | 回溯算法 | 子集型 串联字符串的最大长度1239.串联字符串的最大长度1239. 串联字符串的最大长度 - 力扣(LeetCode) 笔者这道题写的感觉很麻烦,大家可以去看看官方题解 思路: 用选或不选这个思路,会让思路变得非常简单。具体来说就是看选不选当前的字符串,选的话长度加上当前字符串,不选的话就递归下一个字符串选或不选 难点在于 我们决定要选当前字符串的情况下,我们能不能选当前字符串,即看这个字符串和已经选了的有没有重复,除此之外还要看组内有没有重复的 用下面这个函数来检查能不能选当前字符串 遍历字符串,如果在之前选的里面没出现过,对应字符++,如果有字符出现过,那代表我们都将不能选这个字符串,所以直接break for循环结束后,有两种情况,第一种就是i==s.size()这说明我们这个字符串可以选,因为遍历到了最后都没有重复(注意,之后恢复...
Day135 | 灵神 | 回溯算法 | 子集型 烹饪料理
Day135 | 灵神 | 回溯算法 | 子集型 烹饪料理LCP 51.烹饪料理LCP 51. 烹饪料理 - 力扣(LeetCode) 思路: 思路比较好想 笔者用的是选或不选的思路,即看第 i种选或不选,如果食材足够就选(choicei进行判断),如果食材不足就不选,直接去看i+1选或不选 选的话就把食材饱腹感美味度给修改了,不选的话就直接递归就行 完整代码: 1234567891011121314151617181920212223242526272829303132333435363738394041424344class Solution {public: int res=-1; //还够不够选第i种 bool choicei(vector<int>& materials, vector<vector<int>>& cookbooks,int i) { for(int j=0;j<materials.size();j++) ...
Day134 | 灵神 | 回溯算法 | 子集型 字母大小写全排列
Day134 | 灵神 | 回溯算法 | 子集型 字母大小写全排列784.字母大小写全排列784. 字母大小写全排列 - 力扣(LeetCode) 思路: 这道题用选或不选的思路来解答。选或不选说的不是选或不选s字符串中的某个字符,而是选或不选改变s字符串中字符的大小写 如果是数字的话就不用说了,我们直接输入到path就行 如果是字母的话,那就有两种情况 1.选择不改变其大小写直接输入到path,这种就是原来什么样子现在还什么样 2.选择改变其大小写直接输入到path,这种就是改变了大小写以后放进去的 需要注意的点:对于同一个结点有多个状态,比如这道题,在选择字母a之后,字母a还有两个状态一个改变大小写一个不改变。如果是这种情况的话就要把两个状态都给列出来,即小写a输入path后递归一遍,大写a输入path后再递归一遍 完整代码: 1234567891011121314151617181920212223242526272829303132333435363738class Solution {public: vector<string> res; ...
Day133 | 灵神 | 回溯算法 | 子集型 二叉树的所有路径
Day133 | 灵神 | 回溯算法 | 子集型 二叉树的所有路径257.二叉树的所有路径257. 二叉树的所有路径 - 力扣(LeetCode) 思路: 这道题思路比较简单,直接写就行 完整代码: 1234567891011121314151617181920212223class Solution {public: vector<string> res; void dfs(TreeNode *t,string path) { if(t==nullptr) return ; path += to_string(t->val); if(t->left==nullptr&&t->right==nullptr) { res.push_back(path); return ; } path += "->"; ...














