Rocket - core - take_pc

https://mp.weixin.qq.com/s/7YF5cZLYkvo-Dbp30DxwsA

 

简单介绍take_pc相关的实现。

 

本文目录:

1. take_pc

2. 用途

3. 意义

4. take_pc_mem

5. take_pc_wb

6. 总结

 

以下正文:

1. take_pc

take_pc由take_pc_wb和take_pc_mem相或产生:

因为take_pc_wb和take_pc_mem都是wire类型,所以take_pc也是一个wire类型。

 

2. 用途

take_pc同时用于控制ibuf和frontend:

其中:

a. 连接到ibuf的kill信号,使ibuf中的指令变为非法;

b. 连接到frontend的req信号,使其接收新的pc:

 

3. 意义

这里take_pc的用法与通常对流水线pc的理解有较大的不同之处。

通常情况下,流水线中包含一个pc+4的功能,使得pc指向下一个32位宽的指令。这里在某些特殊的情况下,才向frontend发起take新的pc的请求。由此可以推测,在顺序执行的情况下,frontend内部包含一个pc自加的功能,并把获取到的指令返回给ibuf。

 

1) take_pc向frontend发起请求

在frontend中,s0_valid包含两种情况:

a. 随take_pc输入的io.cpu.req.valid为真;

b. 或者是fq包含空间;fq是一个包含5个entry的队列,其中存放了FrontendResp结构:

从中可以看出,即便take_pc没有为真,只要fq未满,仍然可以发起请求,获取指令。而流水线通过ibuf向frontend发起FrontendResp出队请求。这样流水线每取出一条指令,frontend便会自动的通过icache请求一条指令。这里还有一个需要注意的地方,就是take_pc作为fq的复位信号使用,如果take_pc为真,则fq复位,其中缓存的内容被清空。

 

2) pc自加

如果take_pc为真,则io.cpu.npc使用外部输入的io.cpu.req.bits.pc:

如果take_pc为假,则使用自加计算而出的npc。

其中:

a. 不考虑replay的情况,npc = predicted_npc;

b. predicted_npc = ntpc;

c. ntpc = s1_base_pc + fetchBytes.U,这里就包含了自加的动作;

d. s1_base_pc使用s1_pc计算得来,s1_pc是一个寄存器,其值更新使用io.cpu.npc,这就又转回来了,不过根据寄存器的特性,其值要在下一个时钟才会更新;

e. 如此便实现了自加fetchBytes的动作;

 

3) 向tlb发起请求,对pc进行地址转换:

 

4) 向icache发起请求:

 

5) 使用icache返回的数据,存入到fq中:

 

6) fq向ibuf出队:

 

4. take_pc_mem

take_pc_mem表示mem阶段需要改变执行分支的情况。

首先要求mem阶段流水线寄存器的值是合法的。

然后要改变执行分支的情况存在两种:

a. 预测错误:分支预测错误,导致frontend取指及流水线执行的分支出错,需要刷新重新执行;

b. 内存屏障需要刷新流水线;

 

5. take_pc_wb

take_pc_wb表示wb阶段需要改变执行分支的情况。

包含四种情况:

a. 重新执行;

b. 异常或者中断需要跳转以进行处理;

c. eret指令要恢复到正常执行流程;

d. 需要flush流水线的情况;

 

6. 总结

总结一下:如果take_pc为假,则frontend自动顺序取指,流水线执行同一个分支上的指令。如果take_pc为真,则要求frontend切换分支进行跳转,则流水线也要跟着进行切换执行另一条分支上的指令。

 

 

posted @ 2022-03-12 00:01  wjcdx  阅读(134)  评论(0编辑  收藏  举报