cpu设计和实现(流水线暂停)

news2025/1/22 13:12:01

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        前面我们说过,数字电路里面流水线的引入,主要是为了提高数据的处理效率。那么,鉴于此,为什么又要对流水线进行暂停处理呢?直接在某一个阶段,把所有的工作都完成不行吗?举个例子来说,如果指令在exe阶段的时候,同时需要处理乘法和加法(madd指令),那样不是也可以吗。其实,这么做,确实是可以的。但是,真的这么做的话,会大幅度降低时钟运算频率,那样会反而得不偿失了。

1、从verilog到电路

        大家习惯于编写verilog代码。但是本质上来说,这其实也是在设计电路。只不过,我们设计的是数字电路。现在假设有这样一段代码,

reg d;
always @(posedge clk)
	if(a) 
		d <= b;
	else
		d <= c;

        这段代码的功能比较简单。就是说,在每次时钟上升沿发生的时候,如果a为真,将b传递给d;反之,将c传递给d。大家可能在看这段代码的时候,认为只是一个简单的时序电路。其实,这里面既包含了组合逻辑,也包含了时序逻辑,

wire temp;
assign temp = a ? b:c;

reg d;
always @(posedge  clk)
	d <= temp;

        上面的代码换一种写法,这样就比较容易看清楚了。所有的信号都会汇集成temp,也就是一个wire。最终在clk上升沿发生的时候,把temp传递给d。到了这一步,其实继续扩展一下思路,想象下翻译成的最终电路是什么样子的,

         上面这个电路其实就能说明数字电路翻译的基本原理了。如果信号a为真,那么下面c的输入其实无关紧要了。因为此时信号的输出只和b相关;同样而言,如果信号a为假,那么上面b的信号就无关紧要了,输出信号就只和c有关。通过上图可以看出,两个信号都会通过或门直接传递给触发器。这样在时钟沿来的时候,把这个信号传递给d寄存器了。

        可以看到,如果门电路不是很多的时候,那么组合逻辑的延时不是很明显。但是如果时序逻辑之间的组合逻辑过于复杂,那么整个电路的时钟频率是很难拉起来的。这个时候,与其降低时钟频率,不如暂停一下流水线,等待几个时钟反而要划算的多。

2、添加更多的运算指令

        前面一章引入了HI、LO寄存器,这就说明可以添加更多的数学运算指令了,而不仅仅是之前的逻辑运算指令、移位运算指令。常见的简单算术操作都可以添加进来了,比如说add、addi、addiu、addu、sub、subu、clo、clz、slt、slti、sltu、mul、mult、multu。关于乘法,这里有三个指令,分别是mul、mult、multu。注意,mul是把结果保存在通用寄存器里面的,而mult和multu是把运算结果保存在HI、LO寄存器里面的。

        准备必要的汇编代码,

   .org 0x0
   .set noat
   .global _start
_start:

   ######### add\addi\addiu\addu\sub\subu ##########

   ori  $1,$0,0x8000           # $1 = 0x8000
   sll  $1,$1,16               # $1 = 0x80000000
   ori  $1,$1,0x0010           # $1 = 0x80000010

   ori  $2,$0,0x8000           # $2 = 0x8000
   sll  $2,$2,16               # $2 = 0x80000000
   ori  $2,$2,0x0001           # $2 = 0x80000001

   ori  $3,$0,0x0000           # $3 = 0x00000000
   addu $3,$2,$1               # $3 = 0x00000011
   ori  $3,$0,0x0000           # $3 = 0x00000000
   add  $3,$2,$1               # overflow,$3 keep 0x00000000

   sub   $3,$1,$3              # $3 = 0x80000010         
   subu  $3,$3,$2              # $3 = 0xF

   addi $3,$3,2                # $3 = 0x11
   ori  $3,$0,0x0000           # $3 = 0x00000000
   addiu $3,$3,0x8000          # $3 = 0xffff8000

   #########     slt\sltu\slti\sltiu     ##########

   or   $1,$0,0xffff           # $1 = 0xffff
   sll  $1,$1,16               # $1 = 0xffff0000
   slt  $2,$1,$0               # $2 = 1
   sltu $2,$1,$0               # $2 = 0
   slti $2,$1,0x8000           # $2 = 1
   sltiu $2,$1,0x8000          # $2 = 1

   #########          clo\clz          ##########

   lui $1,0x0000          # $1 = 0x00000000
   clo $2,$1              # $2 = 0x00000000
   clz $2,$1              # $2 = 0x00000020

   lui $1,0xffff          # $1 = 0xffff0000
   ori $1,$1,0xffff       # $1 = 0xffffffff
   clz $2,$1              # $2 = 0x00000000
   clo $2,$1              # $2 = 0x00000020

   lui $1,0xa100          # $1 = 0xa1000000
   clz $2,$1              # $2 = 0x00000000
   clo $2,$1              # $2 = 0x00000001

   lui $1,0x1100          # $1 = 0x11000000
   clz $2,$1              # $2 = 0x00000003
   clo $2,$1              # $2 = 0x00000000

   ori  $1,$0,0xffff                  
   sll  $1,$1,16
   ori  $1,$1,0xfffb           # $1 = -5
   ori  $2,$0,6                # $2 = 6
   mul  $3,$1,$2               # $3 = -30 = 0xffffffe2
  
   mult $1,$2                  # hi = 0xffffffff
                               # lo = 0xffffffe2

   multu $1,$2                 # hi = 0x5
                               # lo = 0xffffffe2
   nop
   nop

        翻译成inst_rom.data文件,

34018000
00010c00
34210010
34028000
00021400
34420001
34030000
00411821
34030000
00411820
00231822
00621823
20630002
34030000
24638000
3401ffff
00010c00
0020102a
0020102b
28228000
2c228000
3c010000
70221021
70221020
3c01ffff
3421ffff
70221020
70221021
3c01a100
70221020
70221021
3c011100
70221020
70221021
3401ffff
00010c00
3421fffb
34020006
70221802
00220018
00220019
00000000
00000000

        总共汇编代码有43行,所有生成的汇编指令也有43条。

        做好了所有的准备工作之后,就可以开始分析波形图。依次把pc寄存器、wb寄存器、regfile寄存器、wb_hi&wb_lo寄存器、hi_o&lo_o寄存器拉进来。从第一条指令,向1号寄存器写入0x00008000,接着第二条指令继续向1号寄存器写入0x80000000,这样不断通过阅读寄存器的数值,结合阅读汇编代码,来验证cpu的实现是否正确。如果错误,还要回头看一下中间的时序逻辑和组合逻辑对不对。

        如果希望查看HI和LO寄存器,可以直接选中w_whilo,查看当w_whilo为1的时候,写入的数值是什么,对应的汇编指令是什么,和我们之前的期待是不是一样的。

3、暂停流水线

        之前我们谈到了暂停流水线这个功能,可是怎么实现这个功能呢?一般来说,对于cpu各个执行模块,还会衍生出来一个control模块,这个control模块会控制流水线是暂停,还是flush掉。今天我们讨论的情况仅仅是暂停。而且就是算暂停,也有可能出现一部分暂停、一部分不暂停的情况。

`include "defines.v"

module ctrl(

	input wire										rst,

	input wire                   stallreq_from_id,


	input wire                   stallreq_from_ex,
	output reg[5:0]              stall       
	
);


	always @ (*) begin
		if(rst == `RstEnable) begin
			stall <= 6'b000000;
		end else if(stallreq_from_ex == `Stop) begin
			stall <= 6'b001111;
		end else if(stallreq_from_id == `Stop) begin
			stall <= 6'b000111;			
		end else begin
			stall <= 6'b000000;
		end    
	end      
			

endmodule

         这就是负责对流水线进行仲裁的ctrl模块,它搜集各个模块的请求,又马上给出一个综合的结果进行输出处理。以pc_reg.v为例,


`include "defines.v"

module pc_reg(

	input	wire										clk,
	input wire										rst,

	//来自控制模块的信息
	input wire[5:0]               stall,
	
	output reg[`InstAddrBus]			pc,
	output reg                    ce
	
);

	always @ (posedge clk) begin
		if (ce == `ChipDisable) begin
			pc <= 32'h00000000;
		end else if(stall[0] == `NoStop) begin
		  		pc <= pc + 4'h4;
		end
	end

	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
			ce <= `ChipDisable;
		end else begin
			ce <= `ChipEnable;
		end
	end

endmodule

        没有递增之前,可能pc不停增加就可以了。现在的话,pc需要接收stall的结果,且只有在stall不存在的时候,才能不停递增pc寄存器。

        之前我们提到过madd指令,现在就看看,如果有了这个指令,ex阶段应该怎么处理,

			case (aluop_i) 
				`EXE_MADD_OP, `EXE_MADDU_OP:		begin
					if(cnt_i == 2'b00) begin
						hilo_temp_o <= mulres;
						cnt_o <= 2'b01;
						stallreq_for_madd_msub <= `Stop;
						hilo_temp1 <= {`ZeroWord,`ZeroWord};
					end else if(cnt_i == 2'b01) begin
						hilo_temp_o <= {`ZeroWord,`ZeroWord};						
						cnt_o <= 2'b10;
						hilo_temp1 <= hilo_temp_i + {HI,LO};
						stallreq_for_madd_msub <= `NoStop;
					end
				end

        简单分析下,初次计算madd的时候,cnt_i肯定是0,那么这里肯定显示算一个临时结果hilo_temp_o,同时stallreq_for_madd_msub申请流水线暂停,cnt_o修改为1;等到下一个周期的时候,将之前的hilo_temp_o通过hilo_temp_i重新获取进来,和HI、LO重新做计算,生成hilo_temp1,stallreq_for_madd_msub也恢复。注意,这里cnt_o没有直接设置为2’b00,主要是为了防止其他情形导致流水线暂停的时候,不会出现重复计算的情况发生。

        另外注意,这里的cnt_i、cnt_o都被ex_mem模块保存了。

        一切都准备好了,就可以开始测试了。先准备好汇编文件,


   .org 0x0 
   .set noat 
   .global _start 
_start: 
   ori  $1,$0,0xffff 
   sll  $1,$1,16 
   ori  $1,$1,0xfffb            # $1 = -5  为寄存器$1赋初值 
   ori  $2,$0,6                 # $2 = 6   为寄存器$2赋初值 
 
   mult $1,$2                   # hi = 0xffffffff 
                                # lo = 0xffffffe2 
 
   madd $1,$2                   # hi = 0xffffffff 
                                # lo = 0xffffffc4 
 
   maddu $1,$2                  # hi = 0x5 
                                # lo = 0xffffffa6 
 
   msub $1,$2                   # hi = 0x5 
                                # lo = 0xffffffc4 
 
   msubu $1,$2                  # hi = 0xffffffff 
                                # lo = 0xffffffe2 

        接着就是翻译成二进制文件数据,

3401ffff
00010c00
3421fffb
34020006
00220018
70220000
70220001
70220004
70220005

        有了这一切就可以开始进行波形图的分析了,

        因为涉及到流水线的查看,所以这个时候可以重点观察下stall信号和pc地址的变更。观察发现,210ns的时候ce生效。290ns的时候数据准备写入,写入的地址是寄存器1,写入的数据是0x0000ffff,这和我们观察的汇编指令代码是一致的。

         在350ns的时候,我们发现pc地址出现了暂停,stall信号出现了,这个时候表明处于ex阶段的应该是madd指令。注意,不是mult指令,mult是在不需要流水线暂停的。为了判断我们的分析是否正确,可以把mem_whilo、mem_hi、mem_lo信号加进来。

        可以看到除了第一次mem_whilo为1,是因为乘法运算之后,后面的每一次计算,都需要等待两个周期,mem_hi和mem_lo才会又获得正确的数据。 以此类推,后面的几条指令,都会发生流水线暂停的操作,每次都是暂停1个时钟周期后,又立马回复正常。整个流程就是这样一个结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40554.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ssm宠物商城管理系统源码

在 Internet飞速开展的今天&#xff0c;互联网成为人们快速获取、发布和传 递信息的重要渠道&#xff0c;它在人们学习、工作、生活等各个方面发挥着重要的作用。 因此建立在 Internet应用上的地位显而易见&#xff0c;它已成为政府、企事业单位信息化 建立中的重要组成局部&am…

[附源码]SSM计算机毕业设计网上书店管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【kafka】十五、kafka消费者API

kafka消费者API Consumer消费数据时的可靠性是很容易保证的&#xff0c;因为数据在kafka中是持久化的&#xff0c;故不用担心数据丢失的问题。 由于consumer在消费过程中可能会出现断电宕机的等故障&#xff0c;consumer恢复后&#xff0c;需要从故障前的位置继续消费&#xf…

visual studio 2019 + Qt 开发,使用visual leak detector检测内存泄漏

选择了在vs2019上开发Qt, 遇到了内存泄露问题。还好vs上有方便的visual leak detector&#xff08;vld&#xff09;检测工具。 虽然官网上只支持到vs2015, 但vs2019上也能用。 具体参考这位博主的文章&#xff1a;https://blog.csdn.net/qq_22108657/article/details/1208843…

Redis数据库安装(Windows)

目录 一、下载Windows安装包 二、启动Redis 1.在终端中启动 2.使用start.bat文件启动 3.添加服务启动 三、安装Redis可视化管理工具 1.安装Redis图形客户端 2.连接数据库 一、下载Windows安装包 下载地址&#xff1a;Releases tporadowski/redis GitHub 选择下载相…

单链表的递归详解 (leetcode习题+ C++实现)

文章目录合并两个有序链表翻转链表链表中移除节点合并两个有序链表 传送门&#xff1a; https://leetcode.cn/problems/merge-two-sorted-lists/description/ 题目要求&#xff1b; 给你两个有序的链表&#xff0c;将这两个链表按照从小到大的关系&#xff0c;合并两个链表为…

Mybatis快速入门

Mybatis安装与配置 Mybatis概述 Mybatis本质上是一个别人写好的框架&#xff0c;用于简化 JDBC 开发&#xff0c;通过Mybatis框架&#xff0c;可以极大的降低JDBC的开发难度。 官方文档&#xff1a;https://mybatis.org/mybatis-3/zh/index.html Mybatis快速入门 需求&…

MySQL进阶实战10,MySQL全文索引

一、全文索引 全文索引的目的是 通过关键字的匹配进行查询过滤&#xff0c;基于相似度的查询&#xff0c;而不是精确查询。 全文索引利用分词技术分析出文字中某关键字的频率和重要性&#xff0c;并按照一定的算法智能的筛选出我们想要的结果。 全文索引一般用于字符串中某关…

tomcat服务器安装及配置教程(保姆级教程)

Tomcat安装教程 &#xff08;以tomcat-9.0.62为例&#xff1a;&#xff09; 1.下载安装包 可以从官网下载安装包&#xff1a; &#xff08;1&#xff09;从官网下载 输入网址进入官网 选择版本10&#xff0c;版本9&#xff0c;或者版本8&#xff0c;都可以&#xff0c;这里…

掘金热榜首推!阿里内部都在用的Java后端面试笔记,囊括99%的主流技术

纵观今年的技术招聘市场&#xff0c; Java依旧是当仁不让的霸主 &#xff01;即便遭受 Go等新兴语言不断冲击&#xff0c;依旧岿然不动。究其原因&#xff1a; Java有着极其成熟的生态&#xff0c;这个不用我多说&#xff1b;Java在 运维、可观测性、可监 控性方面都有着非常优…

Spring Boot JPA 本机查询示例

在本教程中&#xff0c;您将了解如何在 Spring 引导中使用 Spring Data JPA 本机查询示例&#xff08;带参数&#xff09;。我将向您展示&#xff1a; 将 Spring JPA 本机查询与Query注释一起使用的方法如何在 Spring 引导中执行 SQL 查询具有 WHERE 条件的 JPA 选择查询示例 …

动态SQL

动态SQL 可以根据具体的参数条件&#xff0c;来对SQL语句进行动态拼接。比如在以前的开发中&#xff0c;由于不确定查询参数是否存在&#xff0c;许多人会使用类似于where 1 1 来作为前缀&#xff0c;然后后面用AND 拼接要查询的参数&#xff0c;这样&#xff0c;就算要查询的…

MongoShake数据灾备与迁移

安装部署 解压 建议部署在离目标端近的地方&#xff0c;比如部署再目标端本地 tar -zxvf mongo-shake-v2.8.1.tgz配置 同构环境下主要参数 启动 执行下述命令启动同步任务&#xff0c;并打印日志信息&#xff0c;-verbose 0表示将日志打印到文件&#xff0c;在后台运行 …

【Linux从入门到放弃】Linux基本指令大全

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《Linux从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; L…

黑苹果之微星(MSI)主板BIOS详细设置篇

很多童鞋安装黑苹果的时候会卡住&#xff0c;大部分原因是cfg lock 没有关闭&#xff0c;以及USB端口或SATA模式设置错误。 为了避免这些安装阶段报错的情况发生&#xff0c;今天给大家分享一下超详细的BIOS防踩坑设置指南--微星&#xff08;MSI&#xff09;主板BIOS篇&#xf…

springcloud总结篇

一.整体结构 springcloud总体架构 对比学习 二.具体 1.场景模拟 订单服务调用库存服务来更新数据库中的库存 2.springcloud问题解析 Eureka OpenFeign &#xff08;RibbonRestTemplate&#xff09; Hystrix Gateway config Bus 订单服务只知道库存服务的名称…

Python测试-unittest,2022-11-27

(2022.11.27 Sun) unittest是Python自带的单元测试框架。unittesthtml和pytestallure(测试报告)成为常用的自动测试和报告的框架组合。 unittest-archi-2022-11-23-2114.png 概念 test case测试用例&#xff1a;测试用例是测试的基本单元&#xff0c;用于测试一组特定输入的特…

OpenCV图像特征提取学习四,SIFT特征检测算法

一、SIFT特征检测概述 SIFT的全称是Scale Invariant Feature Transform&#xff0c;尺度不变特征变换&#xff0c;由加拿大教授David G.Lowe提出的。SIFT特征具有对旋转、尺度缩放、亮度变化等保持不变性&#xff0c;是一种非常稳定的局部特征。 1.1 SIFT算法具的特点 图像…

平衡搜索树——AVL树小记

文章目录二叉搜索树平衡搜索树AVL树定义AVL中平衡(Balance)因子的定义AVL树插入规则AVL树失衡情况左左失衡/右右失衡左右失衡RL失衡代码左旋-调整平衡插入调整平衡因子AVL树正确性的验证二叉搜索树 理想情况下&#xff0c;二叉搜索树的查找时间复杂度是0(log(n)) 但是&#xff…

Linux 进程概念 —— 初识操作系统(OS)

文章目录1. 概念2. 设计操作系统的目的3. 定位4. 如何理解管理5. 再谈操作系统&#x1f351; 硬件部分&#x1f351; 操作系统&#x1f351; 驱动程序&#x1f351; 用户部分&#x1f351; 系统调用接口&#x1f351; 用户接口操作6. 总结1. 概念 任何计算机系统都包含一个基本…