数字IC秋招手撕代码(九)可参数化的多端口寄存器堆设计

数字IC秋招手撕代码(九)可参数化的多端口寄存器堆设计

题目

用verilog设计一个可参数化的寄存器堆,同一时刻输入的写地址互不相同,但读地址可以相同,所有端口都能连续响应读写请求



分析

  • 首先题目要求了是可参数化多端口寄存器堆,需要通过多个端口对寄存器堆读写,这势必要用for循环的方式完成;
  • 其次要根据en、wr信号进行读写状态的区分;
  • 在本题中最为关键的其实是写状态时,din向缓冲区传输的过程,很多朋友可能都会是下列的做法。

genvar i;
generate
for(i=0;i<PORT;i++)begin
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			for(integer j=0;j<DEPTH;j++)
				data[j][WIDTH-1:0] <{(WIDTH){1'b0}};
		end
		else if(en[i] & wr[i])
			data[addr[i][WIDTH-1:0] <= din[i][WIDTH-1:0];
	end
end
endgenerate

上述代码乍一看好像没什么问题,输入也保证了写地址不会相同,但其实data上存在multi drive的问题,电路的角度上是确实存在多个数据同时向同一寄存器写入的问题。

所以需要对din提前mux处理,再将mux的结果写入寄存器,这样才能完美的避免multi drive。


代码

module register_file(
clk,
rst_n,
en,
wr,
addr,
din,
dout
);

parameter       PORT    =   2;
parameter       WIDTH   =   32;
parameter       DEPTH   =   128;
parameter       DEPTH_L =   log2(DEPTH);

input                               clk;
input                               rst_n;
input   [PORT-1:0]                  en;
input   [PORT-1:0]                  wr;
input   [PORT-1:0][DEPTH_L-1:0]     addr;
input   [PORT-1:0][WIDTH-1:0]       din;
output  [PORT-1:0][WIDTH-1:0]       dout;


wire    [DEPTH-1:0][PORT-1:0]   wr_hit;
wire    [DEPTH-1:0][WIDTH-1:0]  din_mux;
reg     [DEPTH-1:0][WIDTH-1:0]  data;
reg     [PORT-1:0][WIDTH-1:0]   dout;


genvar g,h;

generate
    for(g=0;g<DEPTH;g++)begin
        for(h=0;h<PORT;h++)begin
            assign wr_hit[g][h] = en[h] & wr[h] &(addr[h]==g);
        end

        one_hot_mux_2d #(
            .WIDTH(WIDTH),
            .CNT(PORT)
        ) one_hot_mux(
            .din(din),
            .sel(wr_hit[g]),
            .dout(din_mux[g])
        );
    end
endgenerate


always @(posedge clk or negedge rst_n)begin
    integer i;
    if(!rst_n)begin
        for(i=0;i<DEPTH;i++)
            data[i] <= {(WIDTH){1'b0}};
    end
    else begin
        for(i=0;i<DEPTH;i++)begin
            if(wr_hit[i])
                data[i] <= din_mux[i];
        end
    end
end


always @(posedge clk or negedge rst_n)begin
    integer i;
    if(!rst_n)begin
        for(i=0;i<PORT;i++)
            dout[i] <= {(WIDTH){1'b0}};
    end
    else begin
        for(i=0;i<PORT;i++)
            dout[i] <= data[addr[i]];
    end
end

endmodule





版权声明:本文为sz_woshishazi原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。