E203 蜂鸟 RISC-V处理器代码阅读笔记 之 执行单元指令冲突处理Outstanding Instruction Track FiFo e203_exu_oitf.v

**这个文章记录了我学习RISC-V蜂鸟E203处理器的学习历程**

针对代码的学习,我结合自己的理解对每个module的接口,以及内部关键信号做了详细的注释说明
原创不易,请保护版权,须转载请私信通知联系作者,并请注明出处,标出原始链接,谢谢~~~
e203_exu_oitf.v

 /*                                                                      
 Copyright 2017 Silicon Integrated Microelectronics, Inc.                
                                                                         
 Licensed under the Apache License, Version 2.0 (the "License");         
 you may not use this file except in compliance with the License.        
 You may obtain a copy of the License at                                 
                                                                         
     http://www.apache.org/licenses/LICENSE-2.0                          
                                                                         
  Unless required by applicable law or agreed to in writing, software    
 distributed under the License is distributed on an "AS IS" BASIS,       
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and     
 limitations under the License.                                          
 */                                                                      
                                                                         
                                                                         
                                                                         
//=====================================================================
//--        _______   ___
//--       (   ____/ /__/
//--        \ \     __
//--     ____\ \   / /
//--    /_______\ /_/   MICROELECTRONICS
//--
//=====================================================================
// Designer   : Bob Hu
//
// Description:
//  The OITF (Oustanding Instructions Track FIFO) to hold all the non-ALU long
//  pipeline instruction's status and information
//
// ====================================================================
`include "e203_defines.v"

module e203_exu_oitf (
  output dis_ready, //oitf 非满,可以进行派遣,即可以允许指令入oitf

  input  dis_ena, //指令检查完了相关性,需要被派遣,需要写入oitf
  input  ret_ena, //指令完成了结果回写,需要从oitf中弹出

  output [`E203_ITAG_WIDTH-1:0] dis_ptr, // oitf fifo的写地址
  output [`E203_ITAG_WIDTH-1:0] ret_ptr, // oitf fifo的读地址

  output [`E203_RFIDX_WIDTH-1:0] ret_rdidx, // 回写的指令的目的操作数rd的地址
  output ret_rdwen,                         // 回写的指令是否有需要写入的目的操作数rd
  output ret_rdfpu,                         // 回写的指令的目的操作数是否是浮点操作数
  output [`E203_PC_SIZE-1:0] ret_pc,        // 回写的指令的pc值
                      //待派遣指令的信息
  input  disp_i_rs1en, // 待派遣指令是否有rs1操作数
  input  disp_i_rs2en, //                 rs2操作数
  input  disp_i_rs3en, //                 rs3操作数
  input  disp_i_rdwen, //                 rd操作数
  input  disp_i_rs1fpu, // 待派遣指令操作数是否为浮点操作数
  input  disp_i_rs2fpu,
  input  disp_i_rs3fpu,
  input  disp_i_rdfpu,
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rs1idx, //待派遣指令操作数的地址
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rs2idx,
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rs3idx,
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rdidx,
  input  [`E203_PC_SIZE    -1:0] disp_i_pc,     //待派遣指令的pc值
                                //待派遣指令与oitf fifo的内容的比较结果; 
  output oitfrd_match_disprs1,  // rs1和rd有冲突标记
  output oitfrd_match_disprs2,  // rs2和rd有冲突标记
  output oitfrd_match_disprs3,  // rs3和rd有冲突标记
  output oitfrd_match_disprd,   // rd有冲突标记

  output oitf_empty, // oitf fifo的空标记,如果oitf fifo为空,那么表示肯定不会存在冲突
  input  clk,
  input  rst_n
);

  wire [`E203_OITF_DEPTH-1:0] vld_set;
  wire [`E203_OITF_DEPTH-1:0] vld_clr;
  wire [`E203_OITF_DEPTH-1:0] vld_ena;
  wire [`E203_OITF_DEPTH-1:0] vld_nxt;
  wire [`E203_OITF_DEPTH-1:0] vld_r;
  wire [`E203_OITF_DEPTH-1:0] rdwen_r;
  wire [`E203_OITF_DEPTH-1:0] rdfpu_r;
  wire [`E203_RFIDX_WIDTH-1:0] rdidx_r[`E203_OITF_DEPTH-1:0];
  // The PC here is to be used at wback stage to track out the
  //  PC of exception of long-pipe instruction
  wire [`E203_PC_SIZE-1:0] pc_r[`E203_OITF_DEPTH-1:0];

  wire alc_ptr_ena = dis_ena; // 写有效标记,每当dispatch了一条长指令,就要写入oitf fifo
  wire ret_ptr_ena = ret_ena; // 读有效标记,每当写回了一条长指令的结果,就要读出oitf fifo

  wire oitf_full ;
  
  wire [`E203_ITAG_WIDTH-1:0] alc_ptr_r; // fifo 写指针
  wire [`E203_ITAG_WIDTH-1:0] ret_ptr_r; // fifo 读指针

  generate
  if(`E203_OITF_DEPTH > 1) begin: depth_gt1//{ fifo深度设置的大于1的时候才会生成下面的代码
      wire alc_ptr_flg_r;  //这个是写指针转一圈的标记
      wire alc_ptr_flg_nxt = ~alc_ptr_flg_r; // 每当写指针转一圈的时候该标记翻转一下       // fifo的写指针永远指向下一个待写入的地址
      wire alc_ptr_flg_ena = (alc_ptr_r == ($unsigned(`E203_OITF_DEPTH-1))) & alc_ptr_ena; //如果当前写指针是最大地址,有来了一个写有效,那么要更新套圈标记 
      
      sirv_gnrl_dfflr #(1) alc_ptr_flg_dfflrs(alc_ptr_flg_ena, alc_ptr_flg_nxt, alc_ptr_flg_r, clk, rst_n); //注意这个寄存器默认上电为1
      
      wire [`E203_ITAG_WIDTH-1:0] alc_ptr_nxt; // dispatch 这个是oitf fifo的写指针
      
      assign alc_ptr_nxt = alc_ptr_flg_ena ? `E203_ITAG_WIDTH'b0 : (alc_ptr_r + 1'b1); //如果当前写指针是最大地址,有来了一个写有效,要把写指针归0;不然就是自增1
      
      sirv_gnrl_dfflr #(`E203_ITAG_WIDTH) alc_ptr_dfflrs(alc_ptr_ena, alc_ptr_nxt, alc_ptr_r, clk, rst_n); //
      
      
      wire ret_ptr_flg_r; // 跟上面写指针的标记一样,这个是读指针的套圈标记
      wire ret_ptr_flg_nxt = ~ret_ptr_flg_r;
      wire ret_ptr_flg_ena = (ret_ptr_r == ($unsigned(`E203_OITF_DEPTH-1))) & ret_ptr_ena;
      
      sirv_gnrl_dfflr #(1) ret_ptr_flg_dfflrs(ret_ptr_flg_ena, ret_ptr_flg_nxt, ret_ptr_flg_r, clk, rst_n);
      
      wire [`E203_ITAG_WIDTH-1:0] ret_ptr_nxt;  // return pointer 这个是oitf fifo的读指针
      
      assign ret_ptr_nxt = ret_ptr_flg_ena ? `E203_ITAG_WIDTH'b0 : (ret_ptr_r + 1'b1);

      sirv_gnrl_dfflr #(`E203_ITAG_WIDTH) ret_ptr_dfflrs(ret_ptr_ena, ret_ptr_nxt, ret_ptr_r, clk, rst_n);

      assign oitf_empty = (ret_ptr_r == alc_ptr_r) &   (ret_ptr_flg_r == alc_ptr_flg_r); // 如果读写指针在同一个圈里(套圈标记相同),且读写指针相等,fifo为空
      assign oitf_full  = (ret_ptr_r == alc_ptr_r) & (~(ret_ptr_flg_r == alc_ptr_flg_r));// 如果读写指针在不同圈里(套圈标记不同),且读写指针相等,fifo为满
  end//}
  else begin: depth_eq1//}{ 如果oitf深度是1的话   那么读写指针一直都是0
      assign alc_ptr_r =1'b0;
      assign ret_ptr_r =1'b0;
      assign oitf_empty = ~vld_r[0]; // 如果oitf 0中内容无效 fifo为空
      assign oitf_full  = vld_r[0];  // 如果oitf 0中内容有效 fifo为满
  end//}
  endgenerate//}

  assign ret_ptr = ret_ptr_r; // 跟回写操作相关的是ret_ptr,即读指针,每成功写回一条长指令的结果,要读一次oitf
  assign dis_ptr = alc_ptr_r; // 跟派遣操作相关的是dis_ptr, 即写指针,每成功派遣一条长指令,要写一次oitf

  
  // If the OITF is not full, or it is under retiring, then it is ready to accept new dispatch // oitf非空的时候允许写入,或者虽然oitf是满的,但是当前有指令在retiring
  assign dis_ready = (~oitf_full) | ret_ena; // 那么也是可以写入的,也就是说这个fifo支持满状态同时读写
 // To cut down the loop between ALU write-back valid --> oitf_ret_ena --> oitf_ready ---> dispatch_ready --- > alu_i_valid
 //   we exclude the ret_ena from the ready signal //但是下面这个注释又把ret_ena去掉了,目的是为了防止生成入上图路径的逻辑环路
 assign dis_ready = (~oitf_full); //
  
  wire [`E203_OITF_DEPTH-1:0] rd_match_rs1idx; //将待派遣的指令的rd与fifo中的每条指令的rs1比较
  wire [`E203_OITF_DEPTH-1:0] rd_match_rs2idx;//将待派遣的指令的rd与fifo中的每条指令的rs2比较
  wire [`E203_OITF_DEPTH-1:0] rd_match_rs3idx;//将待派遣的指令的rd与fifo中的每条指令的rs3比较
  wire [`E203_OITF_DEPTH-1:0] rd_match_rdidx; //将待派遣的指令的rd与fifo中的每条指令的rd比较

  genvar i;
  generate //{
     
      for (i=0; i<`E203_OITF_DEPTH; i=i+1) begin:oitf_entries//{
     
  
        assign vld_set[i] = alc_ptr_ena & (alc_ptr_r == i); // val_r是一个标记fifo中的各个位有没有效的标记,向fifo中写入值的时候把对应位的有效标记拉高
        assign vld_clr[i] = ret_ptr_ena & (ret_ptr_r == i);
        assign vld_ena[i] = vld_set[i] |   vld_clr[i];
        assign vld_nxt[i] = vld_set[i] | (~vld_clr[i]);
  
        sirv_gnrl_dfflr #(1) vld_dfflrs(vld_ena[i], vld_nxt[i], vld_r[i], clk, rst_n);
        //Payload only set, no need to clear
        sirv_gnrl_dffl #(`E203_RFIDX_WIDTH) rdidx_dfflrs(vld_set[i], disp_i_rdidx, rdidx_r[i], clk);  // val_r有效标记置位的同时,保存长指令的相应信息
        sirv_gnrl_dffl #(`E203_PC_SIZE    ) pc_dfflrs   (vld_set[i], disp_i_pc   , pc_r[i]   , clk);  // 保存指令的rd的地址、pc值、是否有目的操作数、目的操作数是否是浮点型
        sirv_gnrl_dffl #(1)                 rdwen_dfflrs(vld_set[i], disp_i_rdwen, rdwen_r[i], clk);
        sirv_gnrl_dffl #(1)                 rdfpu_dfflrs(vld_set[i], disp_i_rdfpu, rdfpu_r[i], clk);

        assign rd_match_rs1idx[i] = vld_r[i] & rdwen_r[i] & disp_i_rs1en & (rdfpu_r[i] == disp_i_rs1fpu) & (rdidx_r[i] == disp_i_rs1idx);
        assign rd_match_rs2idx[i] = vld_r[i] & rdwen_r[i] & disp_i_rs2en & (rdfpu_r[i] == disp_i_rs2fpu) & (rdidx_r[i] == disp_i_rs2idx);
        assign rd_match_rs3idx[i] = vld_r[i] & rdwen_r[i] & disp_i_rs3en & (rdfpu_r[i] == disp_i_rs3fpu) & (rdidx_r[i] == disp_i_rs3idx);
        assign rd_match_rdidx [i] = vld_r[i] & rdwen_r[i] & disp_i_rdwen & (rdfpu_r[i] == disp_i_rdfpu ) & (rdidx_r[i] == disp_i_rdidx );
                                   //fifo中vld_r有效的内容要跟当前要派遣的指令的操作数值进行比较,从而判断会不会发生冲突
      end//}                       //这里之所以要求rdfpu_r[i] == disp_i_rs1fpu 我理解应该是浮点指令和普通指令的地址不是一套,但地址是会重叠的,
  endgenerate//}

  assign oitfrd_match_disprs1 = |rd_match_rs1idx; // 只要有一个比较结果相同就是存在冲突
  assign oitfrd_match_disprs2 = |rd_match_rs2idx;
  assign oitfrd_match_disprs3 = |rd_match_rs3idx;
  assign oitfrd_match_disprd  = |rd_match_rdidx ;

  assign ret_rdidx = rdidx_r[ret_ptr];  // 当有指令写回的时候,该指令对应的oitf fifo中存放的内容
  assign ret_pc    = pc_r [ret_ptr];
  assign ret_rdwen = rdwen_r[ret_ptr];
  assign ret_rdfpu = rdfpu_r[ret_ptr];

endmodule



你可能感兴趣的:(数字IC前端,cpu设计,verilog)