C910笔记---寄存器重命名方式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

        最近在做C910相关工程,需要明白每一条指令的src地址和dst地址是如何与rtl相对应的,并且如果出现了数据冲突(假相关),C910是如何进行寄存器重命名。


一、C910寄存器

        我们关注的是通用寄存器,也就是在C910中,通用(逻辑)寄存器的数量GPR是32个,但是在RTL代码中,这32个寄存器并不是直接例化一一对应的,因为会存在一些数据冲突,比如说 WAW和WAR,这个时候就需要用到寄存器重命名技术来解决数据相关性,所以在C910的RTL工程中,例化了96个物理寄存器来解决假数据相关。

二、寄存器重命名

(以inst0为例)重命名信号顺序为:dealloc→dealloc0→dealloc_preg0_expand[95:0](此时是one hot编码,用上图preg0模块进行解码)→dealloc_preg0[6:0]→alloc_preg0→rtu_idu_alloc_preg0→ir_inst0_dst_preg(可以看到这个时候,已经将inst0的dst的preg从rtu模块传回了idu模块的ir子模块,而ir模块为重命名模块,所以此时经过重命名的dst的preg已经就绪)→ir_pipedown_inst0_dst_preg→dp_ir_inst0_data[84:78]→is_inst0_create_data[84:78]→entry_dst_rel_preg→x_read_data→is_inst0_read_data→idu_rtu_pst_dis_inst_preg→idu_rtu_pst_dis_inst_preg_expand→d0_preg

1、1392-1411 将Preg0始终视为退休,并且写回并将其映射到X0.(X0即通用寄存器X0)

2、1413-5784 例化剩余的95个物理寄存器。

3、5787-     物理寄存器状态逻辑

   ①5791-5988 复位初始化物理寄存器状态,复位成功后,物理寄存器p0-p31将会被映射到通用寄存器r0-r31,而剩余的64个物理寄存器将被释放,所以前32个物理寄存器reset_mapped的信号拉高,剩余64个物理寄存器的reset_mapped的信号置0.

复位成功后,前32个preg的dst_reg将会对应为0-31,剩余64个preg的dst_reg置为0,即前述的被释放,不被映射。

②5990-6019 将从idu_is模块传来的四个微操作的七位preg_dis(派遣指令)扩展为96位one hot编码

③6022-6028 将传入的四条微操作扩展后,重新进行命名为d0_preg - d3_preg。(这里用d进行命名,是因为这一块要创建dispatch(派遣)信号)

④6031-6126 创建了96个creat_vld信号,由上述d0_preg - d3preg所组成,这里的96个vld信号要作为输入,输入到上面例化的96个物理寄存器中,可以看到该信号作为状态机跳转的的判断

所以vld信号有效跳转只有0001,0010,0100,1000四种情况.

以inst0为例,preg0_dst寄存器为9,所以one hot编码第九位为1,那么在preg9_creat_vld会被赋值为0001,则在上述例化的寄存器编号为9的模块内部上述状态机跳转到第一个状态,inst0的iid,dst_reg,rel_reg全部传入编号9的寄存器中。

⑤6128-6231,是指令写回的信号

该部分信号由iu或lsu传回,代表执行单元执行完毕所发出的写回信号。需要注意所传回的写回信号已经在执行单元转化为one hot编码。他将所有需要写回的寄存器的编号位置全部赋值为1,其余位数为0.之后将每一位作为96个物理寄存器的写回信号输入。

以iu_rtu_ex2_pipe0_wb_preg_expand为例,如果该条指令的preg是第9个,则该onr hot编码9置为1,其余为0,则在下面赋值中,preg9_wb_vld=1,则该1信号会传入上述例化的物理寄存器preg9.来驱动该物理寄存器的写回操作。

⑥6233-6429,是寄存器release信号,也就是寄存器整个状态的最后一级,这里逻辑比较简单,还是以第九个preg为例,在④中0001信号已经传入,所以此时代表inst0在preg9,那么release该指令所对应寄存器时也将release preg9.所以preg9 entry会将release信号输出并转为one hot编码,对应这一部分为preg9_rel_preg_expand,所以最后release_vld信号[9]置为1.然后将release_vld[9]赋值给preg9_release_vld,传回到上述例化的第9个寄存器模块中,作为该模块中状态机跳转的条件。

⑦6431-6533 是dealloc的一些命名逻辑,要想看懂这一部分,要先弄明白96个物理寄存器中五个状态的状态机是如何跳转的。首先看他的跳转状态,共有五个:

下面红色的部分是我的推测。

按理说五个状态,三位就可以表示,但是这里控制case的变量 lifecycle_cur_state[4:0],是五位的,结合该模块另一个语句,

它可以用这个控制信号的每一位去表示当前究竟处于哪一个状态,所以我觉得这里的lifecycle_cur_state[4:0]也是一个one hot编码,00001:dealloc;00010:wf_dealloc; 00100:alloc;01000:retire;10000:release。这样就可以解释通为什么它可以用每一位来代表当前状态。所以可以看到用第0位来表示当前状态是否处于dealloc,也就是当前寄存器可以去分配给新的使用者。

所以回到代码中,可以看到他将96个寄存器中输出的preg_cur_state_dealloc赋值给dealloc,这样通过一个dealloc[95:0]信号就可以判断出当前哪一个物理寄存器可以供分配去使用。

⑧6535-6632  这一部分是preg0的选择逻辑,也就是如何从96个处于dealloc的物理寄存器中选择一个给到preg0.该部分采用的优先级是从p0-p95进行选择。

首先第0个是恒为0,所以永远不会被选择;要想选中preg1,则preg1需要处于dealloc状态,并且[0]为0;后面的同理,以9为例,要想选中,则preg9要从处于dealloc状态,并且[8:0]都必须为0,才可以选中。这样就保证了选中的该寄存器前面所有寄存器都是被使用的,可以节约资源。

⑨6634-6731 这一部分是preg1的选择逻辑。该部分采用的优先级是从p95-p0进行选择。

同样[0]恒为0,永远不会被选中。要想选中preg1,则preg1需要处于dealloc状态,并且[95:2]都需要为0,所以该部分正好与preg0的选择逻辑相反,是从第96个寄存器开始进行选择。可以看作是两种不同的搜索方式。我觉得这种搜索方式也是为了避免preg0和preg1所选择的寄存器重复。

⑩6733-6832 这一部分是preg2的选择逻辑。该部分采用和preg0相同的搜索逻辑,所以为了避免和preg0选择同一个物理寄存器,这里在选择时移除了preg0选择的物理寄存器,

假设preg0选中的是9,那么dealloc和~dealloc0与,dealloc[9]=1,~dealloc0[9]=0,dealloc_no_0[9]的位置变为0,preg2则不会再去选中9.

6834-6933 这一部分是preg3的选择逻辑,采用和preg1相同的搜索逻辑,移除了preg1选择的物理寄存器。但是这一部分代码注释掉了。找了一下,preg3的分配逻辑变为了下图。

这里是采用了寄存器重用的策略,可以避免在寄存器池中频繁地分配和回收寄存器

6939-6941 dealloc preg有效信号。对于dealloc preg0来说,只要dealloc有1,即有空的物理寄存器,既可以进行上述⑧的操作。

这个地方其实就是保证取到的寄存器不会重复的操作

现在考虑一下有没有可能出现preg0和preg1选中同一个物理寄存器的情况,假设要同时选中第9个物理寄存器,preg0选择的时候要保证[0:8]为0;那么此时,preg1选择的时候要保证[95:10]为0,也就是此时除了[9]以外都是0,可以看到dealloc_preg0_vld为1,有效;但是此时dealloc_no_0=dealloc和~dealloc0与,dealloc[9]=1,~dealloc0[9]=0,所以&运算后dealloc_no_0信号为0,则dealloc_preg1_vld为0,说明preg dealloc分配的无效,所以避免了选择相同的寄存器。

dealloc_preg2_vld,可以看到信号中剔除了0,1所选的寄存器,只有除此以外所选择的寄存器才会有效。

6949-6973 这一部分是将上述的所分配的dealloc寄存器赋给one hot编码,并传入解码模块,将96位解码为7位。

6979-6982是dealloc_preg3_vld,下图可以看到,preg3没有自己专属的分配逻辑,而是去复用preg0-preg2。7013-7029,是对dealloc_preg3进行分配的一个逻辑。

 

如果alloc_preg_invalid=0,也就代表alloc_preg有效,那么直接将dealloc_preg0赋给3,否则将dealloc_preg1赋给3(我觉得这里是判断分配给preg0的已经从dealloc进入了alloc,而进入alloc代表着这个preg已经分配给了指令,已经使用过了,所以之前preg0的寄存器可以再次拿来进行dealloc,直接拿来给3进行使用)

7008-7011是preg3的dealloc_vld信号,因为其与0和1还有自身的alloc_invalid的信号相关,所以命名头处加了alloc。与0-2通过dealloc判断不同,因为preg3的赋值依赖于此时0和1是否处于alloc太,所以要满足preg3自身alloc无效,并且0或1其中必须有一个alloc有效,因为0或1其中有一个alloc有效,假设alloc_preg0_vld=0,则代表preg0的alloc有效,则说明此时的preg0的物理寄存器可以拿来给preg3进行复用,下图代码可以说明。此时alloc_preg0_vld=0,那么进入第一个循环,将preg0拿来给preg3使用。

7031-7035 是整体的一个dealloc_vld有效信号。

 

他这里去使用vec来进行运算,其实上面代码可以知道,dealloc_vec就是由dealloc赋值而来,所以这里的dealloc_vld的每一位就代表了上述dealloc过程中所选择的所有寄存器。(可以看到上面这幅图对于向量的分配,考虑了一下dealloc0,dealloc1,dealloc3是否存在相同的情况,按照前面的分析,vld信号已经可以判断不会出现重复的信号,所以这个地方有必要吗?)

7050-7145 将dealloc_vld的每一位拆开作为96个寄存器的输入信号dealloc_vld,这个信号的作用在于在寄存器中可以使寄存器状态由dealloc跳转至wf_alloc

7244-7339 将从idu传来的信号每一位拆开作为96个寄存器的输入信号dealloc_mask,用以判断寄存器写回的操作。

7470-7581 是快速退休写回的一些判断,将在rtu_retir文件中使用,

这里是要恢复重命名表,我们知道重命名操作是将reg映射到preg,所以恢复的过程,也就是将preg index转化为reg index

这里的pregx_dreg,为32位信号,是由该条指令本身的五位reg通过one hot码转化而来。所以96个pregx_dreg信号相同位进行组合,可以得到32个,也就对应了32个通用寄存器。

这里假设r2对应的寄存器为preg9,那么在preg9中,对应的preg9_dreg[2]=1,其余位数为0,所以preg除了9之外,所有的寄存器[2]均为0,则r2_preg_expand[95:0]这个96位的信号只有[2]置为1,之后又对这个96位信号进行了解码操作,将其由96位转化为7位,r2_preg[2]=1。

总共可以解码出32个7位的rx_preg信号,对应了32个通用寄存器,之后将32个7位信号组合成rtu_idu_rt_recover_preg224位信号,这个信号里包含了所有需要恢复的通用寄存器的信息。


总结

这里仅仅是C910中如何对指令微操作dst的地址进行重命名分配的一些理解,更深层次可以去详细阅读C910代码。

猜你喜欢

转载自blog.csdn.net/m0_45287781/article/details/130927779
今日推荐