天天看點

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



           

繼續閱讀