Menu Close

RISC-V LSU,SRAM,GPIO模块(2)D_sram模块

RISC-V CPU中 LOAD, STORE 指令集中对SRAM, 和 GPIO 模块的控制,SRAM ,GPIO 等,都可以看做cpu 的外部存储。在哈佛架构中, 使用数据总线,访存这些外部模块

相关参考文章:

RISC-V 教学教案

RISC-V 地址空间

 

在 RISC-V v2.01 版本中, SRAM, GPIO 等模块在 lsu 模块 当中, lsu 模块作为和cpu 内核连接的接口, 在之后的版本中会做相应的修改, 包括增加总线。 包括总线扩展。 同时将其他外设从当前模块中移出,以便增加更多的外设。目前sram 在地址空间的位置是 0x9000_0000 起始的 256M 空间。SRAM 和 DTCM 是一致的。目前版本中, DTCM 就是由SRAM 这个模块组成的。

%title插图%num

SRAM  代码:

module D_sram
#(
parameter MEM_D_DEEP = 1024, //memory data depth
parameter MEM_D_W = 32, //memory data width
parameter MEM_MSK_W = 4, //memory data mask width
parameter MEM_ADDR_W = 32 //memory address width
)
(
input clk, // 系统时钟

input [ MEM_D_W - 1 : 0 ] din, // 数据写入
input [ MEM_ADDR_W - 1 : 0 ] addr, // 数据总线地址
output [ MEM_ADDR_W - 1 : 0 ] o_D_PC, // 没有使用

input cs, // 模块片选
input we, // 写信号
input [ MEM_MSK_W - 1: 0 ] wem, // 写屏蔽位
// output reg mem_init_rdy,
output [ MEM_D_W - 1: 0 ] dout, // 数据读

input rst_n
);

//===============================================================================
reg [ MEM_D_W - 1: 0 ] mem_r[ 0: MEM_D_DEEP - 1 ];
//===============================================================================
wire ren = cs & ( ~we );
wire [ MEM_MSK_W - 1: 0 ] wen = ( { MEM_MSK_W{ cs & we } } & wem );

reg [ MEM_ADDR_W - 1: 0 ] addr_r = 0;
always @( posedge clk )
addr_r <= addr;

wire [ MEM_ADDR_W - 1: 0 ] addr_mem = {addr[31:2]};

// integer mem_init_addr;
//===============================================================================
genvar wi;
generate
for ( wi = 0; wi < MEM_MSK_W; wi = wi + 1 )
begin: mem_write
always @( posedge clk )
begin
if ( wen[ wi ] )
begin
mem_r[ addr_mem ][ 8 * wi + 7: 8 * wi ] <= din[ 8 * wi + 7: 8 * wi ];
end
end
end
endgenerate
//===============================================================================
wire [ MEM_D_W - 1: 0 ] dout_pre;
wire [ MEM_D_W - 1: 0 ] dout_w;
//assign dout_pre = mem_r[ addr_r ];
assign dout_pre = mem_r[ addr_mem ];

genvar ri;
generate
for ( ri = 0; ri < MEM_D_W; ri = ri + 1 )
begin: mem_read
`ifdef SIM//{
assign dout_w[ ri ] = ( dout_pre[ ri ] === 1'bx ) ? 1'b0 : dout_pre[ ri ];
`else //}{
assign dout_w[ ri ] = dout_pre[ ri ];
`endif//}
end
endgenerate
//===============================================================================
//wire [4:0] data_sft = addr[1:0] * 8;
wire [4:0] data_sft = {addr[1:0], 3'b000};
assign dout = dout_w >> data_sft;

assign o_D_PC = addr_r;
//===============================================================================

endmodule

 

端口介绍:

input clk,                         // 系统时钟 

input [ MEM_D_W - 1 : 0 ] din,     // 数据写入
input [ MEM_ADDR_W - 1 : 0 ] addr, // 数据总线地址

input cs,                          // 模块片选
input we,                          // 写信号
input [ MEM_MSK_W - 1: 0 ] wem,    // 写屏蔽位

output [ MEM_D_W - 1: 0 ] dout,    // 数据读

存储寄存器:

reg [ MEM_D_W – 1: 0 ] mem_r[ 0: MEM_D_DEEP – 1 ];

 

读信号, 写信号:

wire ren = cs & ( ~we );
wire [ MEM_MSK_W – 1: 0 ] wen = ( { MEM_MSK_W{ cs & we } } & wem );

SRAM  地址: 由于当前设备位32bit的设备, 所以输入地址只需要[31:2] ,作为访存的单元。

wire [ MEM_ADDR_W – 1: 0 ] addr_mem = {addr[31:2]};

写数据到存储单元:

genvar wi;
generate
for ( wi = 0; wi < MEM_MSK_W; wi = wi + 1 )
begin: mem_write
always @( posedge clk )
begin
if ( wen[ wi ] )
begin
mem_r[ addr_mem ][ 8 * wi + 7: 8 * wi ] <= din[ 8 * wi + 7: 8 * wi ];
end
end
end
endgenerate

读数据单元:

wire [ MEM_D_W - 1: 0 ] dout_pre;
wire [ MEM_D_W - 1: 0 ] dout_w;
//assign dout_pre = mem_r[ addr_r ];
assign dout_pre = mem_r[ addr_mem ];

genvar ri;
generate
for ( ri = 0; ri < MEM_D_W; ri = ri + 1 )
begin: mem_read
`ifdef SIM//{
assign dout_w[ ri ] = ( dout_pre[ ri ] === 1'bx ) ? 1'b0 : dout_pre[ ri ];
`else //}{
assign dout_w[ ri ] = dout_pre[ ri ];
`endif//}
end
endgenerate

load 指令相关操作: LB,  LH,  LW

wire [4:0] data_sft = {addr[1:0], 3'b000};
assign dout = dout_w >> data_sft;

 

整个SRAM 模块 目前是由d触发器组成, 之后也可以被替换位block memory (IP), 但要注意, block memory 通常需要延迟一个时钟周期,所以在整个cpu 设计中, 一定要注意,需要在状态机,或者流水线中增加一个时钟,作为访存。当然也有其他的方法可以使用。

Posted in FPGA, FPGA, IC, RISC-V, RISC-V IPcore设计, RISC-V 教案, 教材与教案, 文章

发表评论

相关链接