CPU设计实战-第四章实践任务二用阻塞技术解决相关引发的冲突

前言

在lab3的实验环境下,添加lab4的指令测试序列,增加相应代码用阻塞技术解决相关引发的冲突。

实验

其关键点在于控制译码流水级指令前进还是阻塞的条件如何生成,其核心判断处于流水线不同阶段的指令是否存在会引发冲突的“写后读”相关关系。

1.传递执行级、访存级和写回级的目的寄存器号到译码级

我们在译码级判断当前时刻处于执行级、访存级或者写回级的指令的目的操作数的寄存器号是否与译码级源操作数的寄存器号是否相同,所以必须将执行级、访存级和写回级的目的寄存器号直接传递到译码级。在各流水级添加代码如下:

EXE_stage:		
	output [ 4:0] EXE_dest,    //执行级目的操作数寄存器号
	assign EXE_dest = es_dest & {5{es_valid}};     // 建议添加在末尾,下同
	
MEM_stage:	
	output [ 4:0] MEM_dest    //访存级目的操作数寄存器号
	assign MEM_dest = ms_dest & {5{ms_valid}};
	
WB_stage:		
	output [ 4:0] WB_dest      //写回级目的操作数寄存器号
	assign WB_dest = ws_dest & {5{ws_valid}};
	
ID_stage:
	input [ 4:0] EXE_dest,    //执行级目的操作数寄存器号
 	input [ 4:0] MEM_dest,    //访存级目的操作数寄存器号
	input [ 4:0] WB_dest,     //写回级目的操作数寄存器号

并在mycpu_top相应模块的实例化中添加对应的信号:

    //实例化所用线路声明,第一次更改时忘了这一部分…………
	wire [4:0]  EXE_dest;
	wire [4:0]  MEM_dest;
	wire [4:0]  WB_dest;
	//wire es_load_op;
	
   ID_stage:
    //实例化端口的增添
    .EXE_dest       (EXE_dest),
    .MEM_dest       (MEM_dest),
    .WB_dest        (WB_dest),
    //.es_load_op     (es_load_op)     //下面要添加
    EXE_stage:
    //实例化端口的增添
    .EXE_dest       (EXE_dest),
    //.es_load_op     (es_load_op) 
    MEM_stage:
    //实例化端口的增添
    .MEM_dest       (MEM_dest)
    WB_stage:
    //实例化端口的增添
    .WB_dest          (WB_dest)

2.判断是否产生数据相关

我们在译码级得到了当前时刻处于执行级、访存级和写回级的指令的目的操作数的寄存器号后,接下来就要产生相应的逻辑来判断是否产生数据相关,产生数据相关之后,暂停流水线。在译码级添加和修改的代码如下:

/*数据前递增加/修改代码*/
//增加-begin
wire src1_no_rs;    //指令 rs 域非 0,且不是从寄存器堆读 rs 的数据
wire src2_no_rt;    //指令 rt 域非 0,且不是从寄存器堆读 rt 的数据
assign src1_no_rs = 1'b0;
assign src2_no_rt = inst_addiu | load_op | inst_jal | inst_lui;
wire rs_wait;       //与源操作数rs对应的寄存器号一致
wire rt_wait;		//与源操作数rt对应的寄存器号一致
assign rs_wait = ~src1_no_rs & (rs!=5'd0) 
                 & ( (rs==EXE_dest) | (rs==MEM_dest) | (rs==WB_dest) );
assign rt_wait = ~src2_no_rt & (rt!=5'd0)
                 & ( (rt==EXE_dest) | (rt==MEM_dest) | (rt==WB_dest) );
                 
wire inst_no_dest;    //标记指令没有寄存器号
assign inst_no_dest = inst_beq | inst_bne | inst_jr | inst_sw;
//增加-end

//修改-begin
assign dest         = dst_is_r31   ? 5'd31 :
                      dst_is_rt    ? rt    : 
                      inst_no_dest ? 5'd0  : rd;
assign ds_ready_go    = ds_valid & ~rs_wait & ~rt_wait;
//修改-end
/*---------------*/

3.转移计算未完成

还需考虑一种情况,就是转移计算未完成。即当转移指令在译码级时,Load指令在执行级无法获得Load结果,因而转移指令无法计算正确的跳转目标。此时根据课本上面的要求,添加和修改相应的代码,如下:

IF_stage:
	wire         pre_fs_ready_go;  //增加
	wire         br_stall;        //增加
	assign to_fs_valid      = ~reset && pre_fs_ready_go;//修改
	assign pre_fs_ready_go  = ~br_stall;  //增加
	assign {br_stall,br_taken,br_target} = br_bus; //修改
	assign inst_sram_en = to_fs_valid && fs_allowin && ~br_stall; //修改

ID_stage:
	input        es_load_op //表示当前执行级为load指令
	wire         br_stall;        //增加
	wire load_stall;
	assign br_stall = br_taken & load_stall & {5{ds_valid}};  //增加
	assign load_stall = (rs_wait & (rs == EXE_dest) & es_load_op ) ||
                    (rt_wait & (rt == EXE_dest) & es_load_op );  
	assign br_bus       = {br_stall,br_taken,br_target};  //修改

EXE_stage:
	output        es_load_op //表示执行级为load指令

mycpu.h:
	`define BR_BUS_WD       34   //修改

在mycpu_top相应模块的实例化中添加对应的信号:

	//实例化所用线路声明
	wire es_load_op;
	
    ID_stage:
    //实例化端口的增添
    .es_load_op     (es_load_op)
    
    EXE_stage:
    //实例化端口的增添
    .es_load_op     (es_load_op) 
    

实验结果

仿真结果:
launch_simulation: Time (s): cpu = 00:00:09 ; elapsed = 00:00:15 . Memory (MB): peak = 945.371 ; gain = 91.242

过测试:
----PASS!!!
run: Time (s): cpu = 00:00:20 ; elapsed = 00:00:16 . Memory (MB): peak = 945.371 ; gain = 0.000
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小威程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值