此次SRAM的读写仿真并没有进行SRAM的乒乓操作,只是进行了单个SRAM的读写操作,SRAM的读写操作不需要刷新操作,写端口包括:写时钟,写地址,写数据,写使能;读端口包括:读时钟,读地址,读数据,读使能。
其中,写使能和读使能的信号控制较为重要,只有在读使能或者写使能有效的时候,读操作或者写操作才是有效的,所以在进行SRAM的读写逻辑时,要注意写使能与写地址、写数据之间的协调,读使能与读地址、读数据之间的协调。
在写使能信号无效的情况下,就应该停止写地址的自增与数据的写入操作,因为写入无效,数据会自动丢弃,当下一次写使能有效时,不能确定本次写地址的开始地址,使数据的处理出现混乱,在读使能信号的情况下,就应该停止读地址的自增,因为读使能无效,读地址自增也不会有数据输出,当下一个读使能有效时,无法确定当前的读地址,也会使数据发生混乱。
这里,我是这样进行实验的,首先进行写操作,写满后,在进行读操作。写地址由小到大,写数据依次递增,例如,地址位宽为5位,那地址空间就是5’b0到5’b11111,其中数据的位宽是在引用IP核的时候设定的,深度也是在引用IP核的时候设定的。读出来的数据经过FIFO之后传送给串口TX模块,波特率9600(主时钟25MHz)。
调试过程中遇到的问题就是,因为串口的速率和SRAM的读写速率相差太多,在SRAM写FIFO的时候,在FIFO满之后,SRAM并没有停止读写操作,即SRAM的读写操作与FIFO的写操作几乎是独立的,这就导致,写入FIFO的数据不是顺序的而是乱序的,在调试过程中,发现有数据输出,但数据顺序不对,推测读写应该问题不大,主要问题应该是读写控制信号的不协调,经过改进之后,数据可以按预期目的进行打印,我是这样改进的,只进行一次写SRAM操作,写满之后只进行一次读操作,这样的话就避免了SRAM一直读写导致数据被覆盖引起的数据乱序问题。
下面记录一下实验过程:
首先是整个实验的RTL图:
SRAM的配置页面:
SRAM的读写时序仿真图:
从图中我们可以看到当写使能为高电平时(使能信号高电平有效),读使能就为低电平,当读使能为高电平时,写使能就为低电平。
当写使能有效时,写地址和写数据都进行了相应的递增操作,当独有效时,读地址发生相应变化,而写地址和写数据停止变化。
具体地质变化与使能信号的关系请看下图:(注:实验中写地址和写数据都是递增的,读地址是在最高地址递减的,所以我们看到的打印数据应该是递减的)
下图是写使能信号、写数据、写使能信号的时序图:
我们发现,当写使能为高电平的时刻,读使能为低电平,读地址保持不变,且写地址从0地址开始自增,数据开始变化。
下面是SRAM的读时序:
下面是控制模块源代码(需要完整代码的可以留言):
module SRAM_CONTROL( clk, sys_rst, wr_en, wr_data, wr_address, rd_en, rd_address, fifo_wr_req, wrfull ); input clk; input sys_rst; input wrfull; output wr_en; output [7:0] wr_data; output [4:0] wr_address; output rd_en; output [4:0] rd_address; output fifo_wr_req; reg [7:0] wr_data_r; reg [4:0] wr_address_r; reg wr_en_r; reg wr_en_r1; reg [4:0] rd_address_r; reg [4:0] rd_address_r1; reg rd_en_r; reg rd_en_r1; reg rd_en_r2; //写SRAM的地址 [email protected](posedge clk or negedge sys_rst) if(!sys_rst) wr_address_r <= 5'd0; else if((wr_address_r < 5'b11111)&&(wr_en_r)) wr_address_r <= wr_address_r + 1'b1; else if(rd_address_r == 5'd1) wr_address_r <= 5'd0; else wr_address_r <= wr_address_r; //写SRAM数据 [email protected](posedge clk or negedge sys_rst) if(!sys_rst) wr_data_r <= 8'd0; else if((wr_data_r < 8'b1111_1111)&&(wr_address_r < 5'b11111)) wr_data_r <= wr_data_r + 1'b1; else if(wr_data_r == 8'b1111_1111)wr_data_r <= 8'd0; else ; //写使能 [email protected](posedge clk or negedge sys_rst) if(!sys_rst) wr_en_r <= 1'b1; // else if(wr_address_r < 5'b11110) wr_en_r <= 1'b1; else if(wr_address_r != 5'b11111) wr_en_r <= 1'b1; else wr_en_r <= 1'b0; //读SRAM地址//地址倒序读出 [email protected](posedge clk or negedge sys_rst) if(!sys_rst) rd_address_r <= 5'b11111; else if(!wr_en_r) rd_address_r <= rd_address_r - 1'b1; else if(rd_address_r == 5'd0) rd_address_r <= 5'b11111; else rd_address_r <= 5'b11111; [email protected](posedge clk or negedge sys_rst) if(!sys_rst) rd_address_r1 <= 5'd0; else rd_address_r1 <= rd_address_r; //读使能 [email protected](posedge clk or negedge sys_rst) if(!sys_rst) rd_en_r <= 1'b0; else if(wr_address_r == 5'b11111) rd_en_r <= 1'b1; else rd_en_r <= 1'b0; [email protected](posedge clk or negedge sys_rst) if(!sys_rst) begin rd_en_r1 <= 1'b0; rd_en_r2 <= 1'b0; end else begin rd_en_r1 <= rd_en_r; rd_en_r2 <= rd_en_r1; end assign wr_en = wr_en_r; assign wr_data = wr_data_r; assign wr_address = wr_address_r; assign rd_en = rd_en_r; assign rd_address = rd_address_r; assign fifo_wr_req = ((!wrfull)&&rd_en_r2)?1'b1:1'b0; endmodule