> # ♻️ 资源
> **大小:** 117MB
> **文档链接:**[**https://www.yuque.com/sxbn/ks/100010673**](https://www.yuque.com/sxbn/ks/100010673)
> **➡️ 资源下载:**[**https://download.csdn.net/download/s1t16/87425296**](https://download.csdn.net/download/s1t16/87425296)
> **注:更多内容可关注微信公众号【神仙别闹】,如当前文章或代码侵犯了您的权益,请私信作者删除!**
> ![qrcode_for_gh_d52056803b9a_344.jpg](https://cdn.nlark.com/yuque/0/2023/jpeg/2469055/1692147256036-49ec7e0c-5434-4963-b805-47e7295c9cbc.jpeg#averageHue=%23a3a3a3&clientId=u8fb96484-770e-4&from=paste&height=140&id=u237e511a&originHeight=344&originWidth=344&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=8270&status=done&style=none&taskId=ud96bf5f7-fe85-4848-b9c2-82251181297&title=&width=140.1999969482422)
# 1. 实验名称
指令流水仿真程序
# 2. 实验报告作者
# 3. 实验内容
## 3.1. 定义 NK-CPU 指令流水线仿真的基本数据结构
### 3.1.1. 四个锁存器
nkcpuPipelineDlg.cpp
```
// 模拟各段之间的锁存器
// IF/ID
class ifData {
public:
CString PC;
CString IR;
ifData& operator=(ifData x) {
this->PC = x.PC;
this->IR = x.IR;
return *this;
}
};
ifData ifbefore, ifafter;
// ID/EX
class idData {
public:
CString PC;
CString IR;
int A;
int B;
int C;
int Imm;
idData& operator=(idData x) {
this->PC = x.PC;
this->IR = x.IR;
this->A = x.A;
this->B = x.B;
this->C = x.C;
this->Imm = x.Imm;
return *this;
}
};
idData idbefore, idafter;
// EX/MEM
class exData {
public:
CString PC;
CString IR;
int C;
int Imm;
int ALUOutput;
exData& operator=(exData x) {
this->PC = x.PC;
this->IR = x.IR;
this->ALUOutput = x.ALUOutput;
this->C = x.C;
this->Imm = x.Imm;
return *this;
}
};
exData exbefore, exafter;
// MEM/WB
class memData {
public:
CString PC;
CString IR;
int Imm;
int LMD;
int ALUOutput;
memData& operator=(memData x) {
this->PC = x.PC;
this->IR = x.IR;
this->ALUOutput = x.ALUOutput;
this->LMD = x.LMD;
this->Imm = x.Imm;
return *this;
}
};
memData membefore, memafter;
```
五段流水每段之间需要一个锁存器,所以一共是四个分别以锁存器之前的 段名+Data 命名,其中:
- IR 是该段要处理的指令,
- PC 是该指令对应的地址,
- A 是指令的 6-10 位也就是操作数 s ,
- B 是指令的 11-15 位也就是操作数 t ,
- C 是指令的 16-20 位也就是操作数 d ,
- Imm 是指令的后 16 位也就是对应的立即数,
- ALUOutput 是 EX 段 ALU 运算后的输出结果,
- LMD 是 MEM 段取出的数据。
由于没有实现并行操作,是利用串行模拟所以要将锁存器分成两个状态 ××before 和 ××after ,每段从 ××before 读取数据,向 ××after 写入数据,一个时钟周期结束后将 ××after 的值赋予 ××before ,所以我重载了 = 运算符。
## 3.2. 使用 C 语言实现 NK-CPU 指令流水线仿真程序
### 3.2.1. 模拟五段流水
设计的总逻辑依据下图:
![](https://cdn.nlark.com/yuque/0/2024/png/2469055/1714270043210-3096acc1-29c3-44c8-8b47-38c72231bb31.png#averageHue=%23c2bdb4&from=url&id=tqPAJ&originHeight=3024&originWidth=4032&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
《计算机体系结构:量化研究方法(第五版)》 P484
#### 3.2.1.1. IF
nkcpuPipelineDlg.cpp
```
CString CnkcpuPipelineDlg::IF() {
if (ifbefore.IR == "11111111111111111111111111111111") {
ifafter.IR = ifbefore.IR;
return _T("NOP");
}
else {
UpdateData(TRUE);
CString strPC;
strPC.Format(_T("%d"), m_PC);
ifafter.PC = strPC;
m_program.EnsureVisible(m_PC / 4, FALSE);// 滚动到选中行
m_program.SetItemState(m_PC / 4, LVIS_SELECTED, LVIS_SELECTED);// 高亮选中行,其实未聚焦时为灰色
CString code = m_program.GetItemText(m_PC / 4, 1);
ifafter.IR = code.Left(8) + code.Mid(9, 8) + code.Mid(18, 8) + code.Right(8);
if ((idbefore.IR.Left(6) == "100011"
&& ifbefore.IR.Left(6) == "101011"
&& (idbefore.IR.Mid(16, 5) == ifbefore.IR.Mid(6, 5) || idbefore.IR.Mid(16, 5) == ifbefore.IR.Mid(11, 5) || idbefore.IR.Mid(16, 5) == ifbefore.IR.Mid(16, 5))) ||
(idbefore.IR.Left(6) == "100011"
&& (ifbefore.IR.Left(6) == "000000" || ifbefore.IR.Left(6) == "100011")
&& (idbefore.IR.Mid(16, 5) == ifbefore.IR.Mid(6, 5) || idbefore.IR.Mid(16, 5) == ifbefore.IR.Mid(11, 5))) ||
(idbefore.IR.Left(6) == "100011"
&& (ifbefore.IR.Left(6) == "001000" || ifbefore.IR.Left(6) == "000110")
&& idbefore.IR.Mid(16, 5) == ifbefore.IR.Mid(6, 5)))
{
ifafter = ifbefore;
idafter.IR = _T("000000") + idafter.IR.Mid(6, 20) + _T("000000");
}
else if (ifbefore.IR.Left(6) == "000010" || (ifbefore.IR.Left(6) == "000110"&&idafter.A <= 0))
{
m_PC = idafter.Imm;
ifafter.IR = _T("000000") + ifafter.IR.Mid(6, 20) + _T("000000");
}
else
{
m_PC += 4;
}
UpdateData(FALSE);
return strPC;
}
}
```
IF 段取指,利用 ID 判断分支是否成立的结果,如果分支指令成立或者是跳转指令,就将 PC 置为相应地址,这里会有一周期的延迟,所以会读入下一条指令,如果跳转到别处,这条指令就没用了,所以将控制位置 0 ,之后的操作也就不会做了。参照下图中的 IF 段:
![](https://cdn.nlark.com/yuque/0/2024/png/2469055/1714270043333-40fb63d0-42dc-42bd-b09f-9e0eb6eb04b7.png#averageHue=%23c3bfb6&from=url&id=P1iPj&originHeight=3024&originWidth=4032&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
《计算机体系结构:量化研究方法(第五版)》 P484
还有一点就是在 ID 段由于数据冒险会有旁路转发,其中有一种情况不能处理,也就是载入指令的目标寄存器在紧接着的下一条指令中作为源寄存器被调用,这种情况也会有一周期延迟,这需要停顿等待,其实也是将 ID 段的判断结果在这一段使用。所以我就都写在这一段里了。参照下图中的 表C-11 :
![](https://cdn.nlark.com/yuque/0/2024/png/2469055/1714270043451-d29ece3a-321f-48d0-af22-10660c79cd78.png#averageHue=%23c4bfb7&from=url&id=tG1Br&originHeight=2291&originWidth=4032&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
《计算机体系结构:量化研究方法(第五版)》 P481
如果这两种情况均不存在,就将 PC + 4 存入 PC。
#### 3.2.1.2. ID
nkcpuPipelineDlg.cpp
```
CString CnkcpuPipelineDlg::ID() {
if (time < 1)return _T("");
else if (ifbefore.IR.Left(6) == "000000"&&ifbefore.IR.Right(6) == "000000"|| ifbefore.IR == "11111111111111111111111111111111") {
idafter.IR = ifbefore.IR;
return _T("NOP");
}
else {
idafter.PC = ifbefore.PC;
idafter.IR = ifbefore.IR;
idafter.A = m_Reg[bin2num(ifbefore.IR.Mid(6, 5))];
idafter.B = m_Reg[bin2num(ifbefore.IR.Mid(11, 5))];
idafter.C = m_Reg[bin2num(ifbefore.IR.Mid(16, 5))];
idafter.Imm = bin2num(ifbefore.IR.Right(16));
if ((memafter.IR.Left(6) == "000000"|| memafter.IR.Left(6) == "100011")
&& (idafter.IR.Left(6) == "000000" || idafter.IR.Left(6) == "100011" || idafter.IR.Left(6) == "101011" || idafter.IR.Left(6) == "001000" || idafter.IR.Left(6) == "000110")
&& (memafter.IR.Mid(16, 5) == idafter.IR.Mid(6, 5))) {
if (memafter.IR.Left(6) == "000000")idafter.A = memafter.ALUOutput;
神仙别闹
- 粉丝: 4275
- 资源: 7532
最新资源
- Java基于springboot+vue的电影院管理系统源码+数据库(高分项目)
- 永磁同步电机PMSM线性死区补偿仿真模型,该模型特点如下: 死区补偿的研究点主要是两个,一个是怎么判断过零点?一个是补偿值给多少?这个仿真讲的都挺清楚; 通过旋转矢量下的dq电流来计算电流矢量角,来确
- 基于模型预测控制MPC的永磁同步电机MATLAB代码 包含单电流环MPC仿真(仅电流环使用MPC策略,速度环使用PI调节器)、速度环和电流环MPC仿真(速度环和电流环均使用MPC策略,非级联) 不是
- Ripr0-v5曰主题8.3开心版适用于知识付费资源素材博客
- AUTOSAR学习资料 包括AUTOSAR基础知识的介绍 AUTOSAR在simulink中的开发、实现和验证 AUTOSAR操作系统移植方法介绍 基于AUTOSAR的电机控制器软件开发教程
- java毕业设计之校园二手交易系统源码+数据库(高分毕设项目).zip
- Zibll子比主题V8.0新版源码开心版WP知识付费资源博客主题模板
- 三菱动态密码解锁程序 程序功能 1 本程序第一次使用时设请定授权天数\\\"RunDAYs\\\"如90天,系统会在授权日期 2接近倒数5天时,会有一个付款提醒 (标签Approaching-da
- 该书高树高树概述概述时代2136189
- mipi IP核,纯HDL实现,4lane传输 适用于所有型号FPGA芯片,纯逻辑实现 不管是ov还是索尼,只要是mipi协议的都可以使用 提供xilinx zynq和lattice两个型号例程,
- LSTM回归预测,多变量输入,单输出 直接替数据就可以使用,不需要对程序大幅修改 程序内有详细注释,便于理解程序运行 想要点击加好友 程序可以出真实值和预测值对比图,线性拟合图,可以打印多种评
- 基于yolov8的火灾检测部署python实现源码+模型(高分项目).zip
- Java项目-基于SSM的华奥汽车销售集团网源码.zip
- 基于深度强化学习的混合动力汽车能量管理策略 1.利用DQN算法控制电池和发动机发电机组的功率分配 2.状态量为需求功率和SOC,控制量为EGS功率 3.奖励函数设置为等效油耗和SOC维持
- Java项目-基于SSM的进销存管理系统.zip
- 简单的文件共享系统php源码带后台管理无需数据库上传即用
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈