IC知识积累——06_RISCV寄存器组的代码

RISCV寄存器组代码

// Copyright 2017 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the \u201cLicense\u201d); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an \u201cAS IS\u201d 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.


// Engineer:       Antonio Pullini - pullinia@iis.ee.ethz.ch                  //
//                                                                            //
// Additional contributions by:                                               //
//                 Sven Stucki - svstucki@student.ethz.ch                     //
//                 Michael Gautschi - gautschi@iis.ee.ethz.ch                 //
//                                                                            //
// Design Name:    RISC-V register file                                       //
// Project Name:   RI5CY                                                      //
// Language:       SystemVerilog                                              //
//                                                                            //
// Description:    Register file with 31x 32 bit wide registers. Register 0   //
//                 is fixed to 0. This register file is based on latches and  //
//                 is thus smaller than the flip-flop based register file.    //
//                 Also supports the fp-register file now if FPU=1            //
//                                                                            //


module riscv_register_file
#(
  parameter ADDR_WIDTH    = 5,
  parameter DATA_WIDTH    = 32,
  parameter FPU           = 0
)
(
  // Clock and Reset
  input  logic                   clk,
  input  logic                   rst_n,

  input  logic                   test_en_i,

  //Read port R1
  input  logic [ADDR_WIDTH-1:0]  raddr_a_i,
  output logic [DATA_WIDTH-1:0]  rdata_a_o,

  //Read port R2
  input  logic [ADDR_WIDTH-1:0]  raddr_b_i,
  output logic [DATA_WIDTH-1:0]  rdata_b_o,

  //Read port R3
  input  logic [ADDR_WIDTH-1:0]  raddr_c_i,
  output logic [DATA_WIDTH-1:0]  rdata_c_o,

  // Write port W1
  input  logic [ADDR_WIDTH-1:0]   waddr_a_i,
  input  logic [DATA_WIDTH-1:0]   wdata_a_i,
  input  logic                    we_a_i,

  // Write port W2
  input  logic [ADDR_WIDTH-1:0]   waddr_b_i,
  input  logic [DATA_WIDTH-1:0]   wdata_b_i,
  input  logic                    we_b_i
);

   // number of integer registers
   localparam    NUM_WORDS     = 2**(ADDR_WIDTH-1);
   // number of floating point registers
   localparam    NUM_FP_WORDS  = 2**(ADDR_WIDTH-1);
   localparam    NUM_TOT_WORDS = FPU ? NUM_WORDS + NUM_FP_WORDS : NUM_WORDS;
      
   // integer register file
   logic [DATA_WIDTH-1:0]         mem[NUM_WORDS];
   logic [NUM_TOT_WORDS-1:1]      waddr_onehot_a;
   logic [NUM_TOT_WORDS-1:1]      waddr_onehot_b, waddr_onehot_b_q;
   logic [NUM_TOT_WORDS-1:1]      mem_clocks;
   logic [DATA_WIDTH-1:0]         wdata_a_q;
   logic [DATA_WIDTH-1:0]         wdata_b_q;

   logic                          clk_int;

   // fp register file
   logic [DATA_WIDTH-1:0]         mem_fp[NUM_FP_WORDS];

   int                            unsigned i;
   int                            unsigned j;
   int                            unsigned k;
   int                            unsigned l;

   genvar                         x;
   genvar                         y;


   //-----------------------------------------------------------------------------
   //-- YSW ADD  : mem sigs test 
   //-----------------------------------------------------------------------------

   logic    [31:0]          mem_register_ila_0    ;
   logic    [31:0]          mem_register_ila_1    ;
   logic    [31:0]          mem_register_ila_2    ;
   logic    [31:0]          mem_register_ila_3    ;
   logic    [31:0]          mem_register_ila_4    ;
   logic    [31:0]          mem_register_ila_5    ;
   logic    [31:0]          mem_register_ila_6    ;
   logic    [31:0]          mem_register_ila_7    ;
   logic    [31:0]          mem_register_ila_8    ;
   logic    [31:0]          mem_register_ila_9    ;
   logic    [31:0]          mem_register_ila_10   ;
   logic    [31:0]          mem_register_ila_11   ;
   logic    [31:0]          mem_register_ila_12   ;
   logic    [31:0]          mem_register_ila_13   ;
   logic    [31:0]          mem_register_ila_14   ;
   logic    [31:0]          mem_register_ila_15   ;
   logic    [31:0]          mem_register_ila_16   ;
   logic    [31:0]          mem_register_ila_17   ;
   logic    [31:0]          mem_register_ila_18   ;
   logic    [31:0]          mem_register_ila_19   ;
   logic    [31:0]          mem_register_ila_20   ;
   logic    [31:0]          mem_register_ila_21   ;
   logic    [31:0]          mem_register_ila_22   ;
   logic    [31:0]          mem_register_ila_23   ;
   logic    [31:0]          mem_register_ila_24   ;
   logic    [31:0]          mem_register_ila_25   ;
   logic    [31:0]          mem_register_ila_26   ;
   logic    [31:0]          mem_register_ila_27   ;
   logic    [31:0]          mem_register_ila_28   ;
   logic    [31:0]          mem_register_ila_29   ;
   logic    [31:0]          mem_register_ila_30   ;
   logic    [31:0]          mem_register_ila_31   ;

   assign      mem_register_ila_0     =   mem[0 ]      ;
   assign      mem_register_ila_1     =   mem[1 ]      ;
   assign      mem_register_ila_2     =   mem[2 ]      ;
   assign      mem_register_ila_3     =   mem[3 ]      ;
   assign      mem_register_ila_4     =   mem[4 ]      ;
   assign      mem_register_ila_5     =   mem[5 ]      ;
   assign      mem_register_ila_6     =   mem[6 ]      ;
   assign      mem_register_ila_7     =   mem[7 ]      ;
   assign      mem_register_ila_8     =   mem[8 ]      ;
   assign      mem_register_ila_9     =   mem[9 ]      ;
   assign      mem_register_ila_10    =   mem[10]      ;
   assign      mem_register_ila_11    =   mem[11]      ;
   assign      mem_register_ila_12    =   mem[12]      ;
   assign      mem_register_ila_13    =   mem[13]      ;
   assign      mem_register_ila_14    =   mem[14]      ;
   assign      mem_register_ila_15    =   mem[15]      ;
   assign      mem_register_ila_16    =   mem[16]      ;
   assign      mem_register_ila_17    =   mem[17]      ;
   assign      mem_register_ila_18    =   mem[18]      ;
   assign      mem_register_ila_19    =   mem[19]      ;
   assign      mem_register_ila_20    =   mem[20]      ;
   assign      mem_register_ila_21    =   mem[21]      ;
   assign      mem_register_ila_22    =   mem[22]      ;
   assign      mem_register_ila_23    =   mem[23]      ;
   assign      mem_register_ila_24    =   mem[24]      ;
   assign      mem_register_ila_25    =   mem[25]      ;
   assign      mem_register_ila_26    =   mem[26]      ;
   assign      mem_register_ila_27    =   mem[27]      ;
   assign      mem_register_ila_28    =   mem[28]      ;
   assign      mem_register_ila_29    =   mem[29]      ;
   assign      mem_register_ila_30    =   mem[30]      ;
   assign      mem_register_ila_31    =   mem[31]      ;
   //-----------------------------------------------------------------------------
   //-- READ : Read address decoder RAD
   //-----------------------------------------------------------------------------
   if (FPU == 1) begin
      assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]];
      assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]];
      assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]];
   end else begin
      assign rdata_a_o = mem[raddr_a_i[4:0]];
      assign rdata_b_o = mem[raddr_b_i[4:0]];
      assign rdata_c_o = mem[raddr_c_i[4:0]];
   end     

   //-----------------------------------------------------------------------------
   // WRITE : SAMPLE INPUT DATA
   //---------------------------------------------------------------------------

   cluster_clock_gating CG_WE_GLOBAL
     (
      .clk_i     ( clk             ),
      .en_i      ( we_a_i | we_b_i ),
      .test_en_i ( test_en_i       ),
      .clk_o     ( clk_int         )
      );

   // use clk_int here, since otherwise we don't want to write anything anyway
   always_ff @(posedge clk_int, negedge rst_n)
     begin : sample_waddr
        if (~rst_n) begin
           wdata_a_q        <= '0;
           wdata_b_q        <= '0;
           waddr_onehot_b_q <= '0;
        end else begin
           if(we_a_i)
             wdata_a_q <= wdata_a_i;

           if(we_b_i)
             wdata_b_q <= wdata_b_i;

           waddr_onehot_b_q <= waddr_onehot_b;
        end
     end

   //-----------------------------------------------------------------------------
   //-- WRITE : Write Address Decoder (WAD), combinatorial process
   //-----------------------------------------------------------------------------
   always_comb
     begin : p_WADa
        for(i = 1; i < NUM_TOT_WORDS; i++)
          begin : p_WordItera
             if ( (we_a_i == 1'b1 ) && (waddr_a_i == i) )
               waddr_onehot_a[i] = 1'b1;
             else
               waddr_onehot_a[i] = 1'b0;
          end
     end

   always_comb
     begin : p_WADb
        for(j = 1; j < NUM_TOT_WORDS; j++)
          begin : p_WordIterb
             if ( (we_b_i == 1'b1 ) && (waddr_b_i == j) )
               waddr_onehot_b[j] = 1'b1;
             else
               waddr_onehot_b[j] = 1'b0;
          end
     end

   //-----------------------------------------------------------------------------
   //-- WRITE : Clock gating (if integrated clock-gating cells are available)
   //-----------------------------------------------------------------------------
   generate
      for(x = 1; x < NUM_TOT_WORDS; x++)
        begin : CG_CELL_WORD_ITER
           cluster_clock_gating CG_Inst
             (
              .clk_i     ( clk_int                               ),
              .en_i      ( waddr_onehot_a[x] | waddr_onehot_b[x] ),
              .test_en_i ( test_en_i                             ),
              .clk_o     ( mem_clocks[x]                         )
              );
        end
   endgenerate
   
   //-----------------------------------------------------------------------------
   //-- WRITE : Write operation
   //-----------------------------------------------------------------------------
   //-- Generate M = WORDS sequential processes, each of which describes one
   //-- word of the memory. The processes are synchronized with the clocks
   //-- ClocksxC(i), i = 0, 1, ..., M-1
   //-- Use active low, i.e. transparent on low latches as storage elements
   //-- Data is sampled on rising clock edge

   // Integer registers
   always_latch
     begin : latch_wdata
        // Note: The assignment has to be done inside this process or Modelsim complains about it
        mem[0] = '0;

        for(k = 1; k < NUM_WORDS; k++)
          begin : w_WordIter
             if(mem_clocks[k] == 1'b1)
               mem[k] = waddr_onehot_b_q[k] ? wdata_b_q : wdata_a_q;
          end
     end
   
   if (FPU == 1) begin
   // Floating point registers
   always_latch
     begin : latch_wdata_fp
        if (FPU == 1) begin
           for(l = 0; l < NUM_FP_WORDS; l++)
             begin : w_WordIter
                if(mem_clocks[l+NUM_WORDS] == 1'b1)
                  mem_fp[l] = waddr_onehot_b_q[l+NUM_WORDS] ? wdata_b_q : wdata_a_q;
             end
        end
     end
   end
endmodule

其中包含了各种技巧:
1、用parameter常数来控制assign的选取:

   //-----------------------------------------------------------------------------
   //-- READ : Read address decoder RAD
   //-----------------------------------------------------------------------------
   if (FPU == 1) begin
      assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]];
      assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]];
      assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]];
   end else begin
      assign rdata_a_o = mem[raddr_a_i[4:0]];
      assign rdata_b_o = mem[raddr_b_i[4:0]];
      assign rdata_c_o = mem[raddr_c_i[4:0]];
   end 

2、时钟门控原语,可用于时钟的暂停于信号采样

 //-----------------------------------------------------------------------------
   // WRITE : SAMPLE INPUT DATA
   //---------------------------------------------------------------------------

   cluster_clock_gating CG_WE_GLOBAL
     (
      .clk_i     ( clk             ),
      .en_i      ( we_a_i | we_b_i ),
      .test_en_i ( test_en_i       ),
      .clk_o     ( clk_int         )
      );

   // use clk_int here, since otherwise we don't want to write anything anyway
   always_ff @(posedge clk_int, negedge rst_n)
     begin : sample_waddr
        if (~rst_n) begin
           wdata_a_q        <= '0;
           wdata_b_q        <= '0;
           waddr_onehot_b_q <= '0;
        end else begin
           if(we_a_i)
             wdata_a_q <= wdata_a_i;

           if(we_b_i)
             wdata_b_q <= wdata_b_i;

           waddr_onehot_b_q <= waddr_onehot_b;
        end
     end

3、for循环的使用

   //-----------------------------------------------------------------------------
   //-- WRITE : Write Address Decoder (WAD), combinatorial process
   //-----------------------------------------------------------------------------
   always_comb
     begin : p_WADa
        for(i = 1; i < NUM_TOT_WORDS; i++)
          begin : p_WordItera
             if ( (we_a_i == 1'b1 ) && (waddr_a_i == i) )
               waddr_onehot_a[i] = 1'b1;
             else
               waddr_onehot_a[i] = 1'b0;
          end
     end

   always_comb
     begin : p_WADb
        for(j = 1; j < NUM_TOT_WORDS; j++)
          begin : p_WordIterb
             if ( (we_b_i == 1'b1 ) && (waddr_b_i == j) )
               waddr_onehot_b[j] = 1'b1;
             else
               waddr_onehot_b[j] = 1'b0;
          end
     end

   //-----------------------------------------------------------------------------
   //-- WRITE : Clock gating (if integrated clock-gating cells are available)
   //-----------------------------------------------------------------------------
   generate
      for(x = 1; x < NUM_TOT_WORDS; x++)
        begin : CG_CELL_WORD_ITER
           cluster_clock_gating CG_Inst
             (
              .clk_i     ( clk_int                               ),
              .en_i      ( waddr_onehot_a[x] | waddr_onehot_b[x] ),
              .test_en_i ( test_en_i                             ),
              .clk_o     ( mem_clocks[x]                         )
              );
        end
   endgenerate
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

俺是菜鸡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值