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