阻塞流水线实现加法器

本文介绍了流水线技术的基本原理,通过实例展示了无阻塞和带阻塞信号的三级流水线设计。接着,详细阐述了四级流水线如何实现8位加法器,最后探讨了在加法器中如何通过停止信号来控制流水线的暂停,以适应处理异常或暂停需求。这种技术对于提高处理器效率和灵活性具有重要意义。

1. 流水线简介

流水线的设计实际上是把规模较大、层次较多的组合逻辑电路分为几级,在每一级插入寄存器组并暂存中间数据。
K级流水线就是从组合逻辑的输入到输出恰好有K个寄存器组(分为K级,每一级都有一个寄存器组),上一级的输出是下一级的输入而又无反馈的电路。

2. 普通三级流水线

无阻塞流水线其实就是依次串接起来的多组触发器。

module no_stall_pipeline (
	input		wire		clk,
	//
	input		wire		[7:0]	din,
	
	output		wire		[7:0]	dout
);


	reg		[7:0]	pipe1_data;
	reg		[7:0]	pipe2_data;
	reg		[7:0]	pipe3_data;
	
	
	always @ (posedge clk)
		pipe1_data	<=	din;
	
	always @ (posedge clk)
		pipe2_data	<=	pipe1_data;
		
	always @ (posedge clk)
		pipe3_data	<=	pipe2_data;
		
	
	assign	dout = pipe3_data;
	
endmodule

3. 带阻塞信号的三级流水

简单的流水线相当于是对输入进行打拍,但实际上很多时候流水线都会被阻塞,比如在实现CPU多周期指令的时候,需要暂停流水。这就意味着一旦后面的流水线被阻塞,前面的流水线也立刻被阻塞。因为此时后面的流水线不通,不能从输入读入新数据,所以前面的流水线必须把原有的数据保持在本级流水线(即被阻塞)。若前一级还在往后送数据,那就会导致数据丢失。
为了使流水线能够应对阻塞,需要设法把数据保持在一级流水级,可以仿照带使能的触发器的时序行为特征。只要触发器的使能信号无效,不管输入端的数据发生什么变化,它的内部存储的数据就保持不变。
可以为每一级流水线设置监管,从前后级接收状态并向前后级发送状态,根据前后级的情况决定下一时刻是否向下传递数据。
对某一级流水线而言,它会向后一级发送一个“下一时刻我有数据传递给你”的请求,也会向前一级发送一个“下一个时刻我可以接收数据”的反馈,然后它也会收到从后一级送来的“是否可以接收数据“的反馈,也会收到从前一级送来的”是否有数据传递过来“的请求。如果某一级流水线当前时刻有数据并且想在下一时刻传递给后一级流水线,但是后一级说它不能接收,那么该级流水线在下一时刻就要保持当前时刻的数据,就产生了阻塞。
在这里插入图片描述

  • pipeX_valid:当前级是否存在有效的数据,高有效。在需要清空流水线的时候不需要把数据域的值置为无效,只需要将valid拉低,代表数据无效,可以节约逻辑资源。
  • pipeX_allowin:第X级传给第X-1级的状态,是否可以接收上一级的数据。
  • pipeX_ready_go:描述第X级的状态,1表示第X级的处理任务已经完成,可以传给X+1级。在实现多周期任务的时候,在最终结果没有得到的时候,可以将这个信号拉低表示暂停住了。
  • pipeX_to_pipeX+1_valid:从第X级传递给第X+1级,1表示下一时刻第X级有数据传递给第X+1级。

下面的例子将ready_go信号持续拉高,表示没有阻塞暂停,回头需要阻塞的时候就控制这个信号。

设计的逻辑如下,out_allowin,validin始终为1,也就相当于只是对数据进行打两拍。

  • 当前级能否进入下一级:始终可以
  • 当前级能否接受:当前级值无效或当前级可以进入下一级,并且下一级可以接收
  • 本级能否转移:本级值有效,并且可以传入下一级
module stallable_pipeline
#(
	parameter	width = 8
)
(
	input	wire					clk,
	input	wire					rst,
	input	wire					validin,
	input	wire	[width-1 : 0]	datain,
	input	wire					out_allow,
	
	output	wire					validout,
	output	wire	[width-1 : 0]	dataout
);

	// pipeX_valid:当前级是否存在有效的数据
	reg						pipe1_valid;
	reg		[width-1 : 0]	pipe1_data;
	reg						pipe2_valid;
	reg		[width-1 : 0]	pipe2_data;
	reg						pipe3_valid;
	reg		[width-1 : 0]	pipe3_data;
	
	/* ************************* pipe1 ************************* */
	// pipe1是否能接收上一级的数据,被刷新
	wire			pipe1_allowin;
	// pipe1是否可以用于传递给下一级,刷新下一级
	wire			pipe1_ready_go;
	// pipe1是否可以进入pipe2
	wire			pipe1_to_pipe2_valid;
	
	// 设为1,表示没有暂停
	assign	pipe1_ready_go	=	1'b1;
	// pipe1的值无效,或要传给下一轮,那么就pipe1可以接受新数据
 	assign	pipe1_allowin	=	!pipe1_valid || pipe1_ready_go && pipe2_allowin;
	// pipe1有效,并且pipe1可以进行传递,那么pipe1_to_pipe2_valid拉高
	assign	pipe1_to_pipe2_valid	=	pipe1_valid && pipe1_ready_go;
	
	always @ (posedge clk)
		begin
			// 清空流水线,pipe1_valid置0,表示pipe1的数据无效
			if (rst == 1'b1)
				pipe1_valid	<=	1'b0;
			// pipe1刷新新值
			// 如果输入端有输入,代表pipe1_valid的数据有效
			// 如果没有输入,代表数据无效
			else	if (pipe1_allowin)
				pipe1_valid	<=	validin;
			
			// 如果输入的值有效,并且pipe1可以接收,那么就从输入端读入
			if (validin && pipe1_allowin)
				pipe1_data	<=	datain;
		end
		
		
	/* ************************* pipe2 ************************* */
	// 是否可以接收
	wire			pipe2_allowin;
	// 是否可以用于向下传递
	wire			pipe2_ready_go;
	// pipe2是否可以进入pipe3
	wire			pipe2_to_pipe3_valid;
	
	// 设为1,表示没有暂停
	assign	pipe2_ready_go	=	1'b1;
 	assign	pipe2_allowin	=	!pipe2_valid || pipe2_ready_go && pipe3_allowin;
	assign	pipe2_to_pipe3_valid	=	pipe2_valid && pipe2_ready_go;
	
	always @ (posedge clk)
		begin
			if (rst == 1'b1)
				pipe2_valid	<=	1'b0;
			else	
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值