Menu Close

RISC-V LSU,SRAM,GPIO Module(2)D_sram Module

The LOAD and STORE instructions in the RISC-V CPU control the SRAM and GPIO modules, SRAM, GPIO, etc., can be regarded as the external storage of the cpu. In the Harvard architecture, use the data bus to access these external modules

Related reference articles:

RISC-V teaching plan

RISC-V address space

 

In the RISC-V v2.01 version, SRAM, GPIO and other modules are in the lsu module. The lsu module is used as the interface to connect with the cpu core. Corresponding modifications will be made in subsequent versions, including adding a bus. Includes bus expansion. Also remove other peripherals from the current module so that more peripherals can be added. At present, the location of sram in the address space is 0x9000_0000, which is actually 256M space. SRAM and DTCM are identical. In the current version, the DTCM is composed of the SRAM module.

SRAM code:

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, // system clock 

    input [ MEM_D_W - 1 : 0 ] din,        // data write 
    input [ MEM_ADDR_W - 1 : 0 ] addr,    // data bus address 
    output [ MEM_ADDR_W - 1 : 0 ] o_D_PC, // not using 

    input cs,                       // module chip select 
    input we,                       // write signal 
    input [ MEM_MSK_W - 1: 0 ] wem, // write mask bit 
    // output reg mem_init_rdy, 
    output [ MEM_D_W - 1: 0 ] dout, // data read 

    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

 

Port introduction:

input clk , // system clock

input [ MEM_D_W – 1 : 0 ] din , // data write
input [ MEM_ADDR_W – 1 : 0 ] addr , // data bus address

input cs , // module chip selection
input we , // Write signal
input [ MEM_MSK_W – 1: 0 ] wem , // write mask bit

output [ MEM_D_W – 1: 0 ] dout , // data read

Storage register:

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

 

Read signal, write signal:

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

SRAM address: Since the current device is a 32-bit device, the input address only needs to be [31:2], as the memory access unit.

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

Write data to the storage unit:

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

Read data unit:

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 instruction related operations: LB, LH, LW

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

 

The entire SRAM module is currently composed of d flip-flops, which can also be replaced by block memory (IP) later, but it should be noted that block memory usually needs to be delayed by one clock cycle, so in the entire CPU design, it must be noted that it needs to be in The state machine, or adding a clock to the pipeline, acts as memory access. Of course, there are other methods that can be used.

Posted in FPGA, RISC-V, RISC-V Textbook, Textbook and Training Project

Related Articles

Leave a Reply

Your email address will not be published.

Leave the field below empty!