差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
book_excise_sram_if [2021/08/20 10:24]
zili
book_excise_sram_if [2021/08/20 13:57] (当前版本)
zili
行 1: 行 1:
 ## SRAM接口实验 ## SRAM接口实验
  
-### 实验内容+### 1. 实验内容 
 +本实验的目的是熟悉SRAM的工作原理,并能够通过编程来访问SRAM。本实验利用VHDL或Verilog编程访问开发系统核心板上的SRAM IS61LV24516,要求:\\ 
 +1. 依次向SRAM中的每个地址写入一个数,然后将此数从该地址中读出,判断写入的数和读出的数是否正确;向每个地址中写入的数从0开始依次加1。\\ 
 +2. 如果对某个地址写入的数和读出的数相同,则LED0缓慢闪烁,每2秒闪烁一次,表示读写正确;如果对某个地址写入的数和读出的数不同,则LED7快速闪烁,每0.4秒闪烁一次,表示读写错误。
  
 +\\
 +\\
 +### 2. 实验原理
 +SRAM是英文Static RAM的缩写,即静态存储器。它是一种具有静态存取功能的存储器,不需要刷新电路即能保存它内部存储的数据。SRAM访问速度快,不必配合内存刷新电路,可提高整体的工作速度。但SRAM集成度低,功耗较大,相同的容量下体积较大,而且价格较高,少量用于关键性系统以提高效率。\\
 +SRAM按是否需要时钟又分为同步SRAM和异步SRAM。同步SRAM采用一个输入时钟来启动存储器的所有事务处理(读、写等);而异步SRAM并不具备时钟输入,通过监视输入以获取来自控制器的命令,一旦识别出某条命令,SRAM将立即执行命令。\\
 +开发系统核心板上的SRAM IS61LV24516为异步SRAM,无时钟信号,管脚定义如表13-1所示。
 +<WRAP centeralign>​
 +**表13-1 SRAM管脚定义**
 +</​WRAP>​
 +|A0~A17|访问SRAM的地址,18位,地址空间为256K。|
 +|I/​O0~I/​O1L12,​L11|数据线,16位宽,SRAM的总容量为512K字节。|
 +|CE|片选信号,低电平有效。|
 +|OE|读使能信号,低电平有效。|
 +|WE|写使能信号,低电平有效。|
 +|LB|低8位访问控制信号,低电平有效。如果LB为0则表示访问16位数据的低8位。|
 +|UB|高8为访问控制信号,低电平有效。如果UB为低则表示访问16为数据的高8位。|
 +
 +图13-1给出了各管脚的详细功能说明。
 +{{ :​图13-1.png |图13-1 ​ 管脚详细功能定义}}
 +<WRAP centeralign>​
 +**图13-1 ​ 管脚详细功能定义**
 +</​WRAP>​
 +
 +SRAM的写入时序如图13 2所示。
 +{{ :​图13-2.png |图13-2 SRAM写入时序}}
 +<WRAP centeralign>​
 +**图13-2 SRAM写入时序**
 +</​WRAP>​
  
 +在进行写入操作时,CE、WE为低,OE为高,在Address上输出要写入的地址,对于UB、LB可以根据访问数据的需要来设置。在WE信号拉低tHZWE时间后SRAM在数据线(Dout)上输出高阻,在此之前信号是不确定的;在数据线输出高阻之后,FPGA可以在数据线(Din)上输出要写入的数据。为了保证不会发生数据冲突,要求FPGA在tHZWE时间后才可以输出要写入的数据。写入时序时间要求如表13 2所示。
 +<WRAP centeralign>​
 +**表13-2 写入时序时间要求**
 +</​WRAP>​
 +{{ :​图13-3.png |表13-2 写入时序时间要求}}
  
 +SRAM的读取时序如图13-3所示。
 +{{ :​图13-4.png |图13-3 SRAM写入时序}}
 +<WRAP centeralign>​
 +**图13-3 SRAM读取时序**
 +</​WRAP>​
  
 +在读取操作时要求,OE和CE为低,LB和UB根据需要设置电平,在Address上输出要读取数据的地址,在max{tAA,​ tACE, tBA}时间后,数据线上输出要读取的数据。读取时序时间要求如表13 3所示。
 +<WRAP centeralign>​
 +**表13-3 读取时序时间要求**
 +</​WRAP>​
 +{{ :​图13-5.png |表13-3 读取时序时间要求}}
 \\ \\
 \\ \\
-### 原理+### 3. 程序设计 
 +#### 3.1 总体架构(SRAM.v) 
 +{{ :​图13-6.png |图13-4 程序总体架构}} 
 +<WRAP centeralign>​ 
 +**图13-4 程序总体架构** 
 +</​WRAP>​ 
 +程序由四个模块组成(图 13-4):clkgen、SRAM_Tester、SRAM_IF和LED_indicator:\\ 
 +1) 由于核心板上的SRAM是异步SRAM, SRAM_IF将SRAM的异步接口转换成同步接口,SRAM_IF可以作为一个通用模块供其它模块调用。\\ 
 +2) SRAM_Tester是对SRAM进行测试,对每一个地址写入一个数据,同时读取该地址的数据,检测和写入的数据是否一致。\\ 
 +3) SRAM_Tester检测结果通知LED_indicator,用LED来指示读写是否正确。\\ 
 +4) Clkgen是一个PLL,将50MHz的输入时钟信号变成100MHz的时钟信号,以证SRAM的高速访问性能。
  
 +#### 3.2 SRAM_IF模块(SRAM_IF.v)
 +SRAM_IF的功能是将SRAM的异步接口转换成同步接口,提供一个同步总线接口的SRAM访问模块。由于FPGA的设计主要是同步设计,转换成同步接口易于被其它模块所使用,提高设计的易用性和可靠性。
  
 +SRAM的接口定义如下:
 +<code verilog> ​
  
 +input clk, reset;​  ​ //​时钟和复位输入信号。
  
 +//​以下信号为总线侧接口信号。
 +input bus_en; //​SRAM访问使能信号,高电平有效。
 +input bus_RW; //​SRAM读写控制信号,高电平为读取访问,低电平为写入访问。
 +input [17:0] bus_addr; //​SRAM访问地址。
 +input [15:0] bus_datain; //​写入SRAM的数据。
 +output [15:0] bus_dataout;​ //​从SRAM中读取的数据。
 +output bus_dataready;​ //​从SRAM中读取数据完成,高电平有效。
 +
 + //​以下信号为SRAM的接口信号,各信号含义如表13-1所示。
 +output ce_i, oe_i, we_i, lb_i, ub_i;
 +inout wire  [15:​0] data_i;​
 +output [17:0] addr_i;
  
-\\ +</​code>​
-\\ +
-### 程序设计+
  
 +{{ :​图13-7.png |图13-5 SRAM_IF写入时序}}
 +<WRAP centeralign>​
 +**图13-5 SRAM_IF写入时序**
 +</​WRAP>​
  
 +总线侧接口控制信号bus_en、bus_rw的宽度为一个时钟周期,期间地址线和数据线有效。在接收到写控制信号时,SRAM_IF将SRAM控制信号ce_i、we_i、oe_i、lb_i、ub_i拉低,同时输出地址信号addr_i,在下一个时钟周期输出数据。因为在写控制信号输出一段时间后SRAM才会置数据线为高阻,这时才可以在数据线上输出要写入的数据信号。
  
-\\ +SRAM_IF的读取时序如图13-6所示。
-\\ +
-### 仿真结果+
  
 +{{ :​图13-8.png |图13-6 SRAM_IF读取时序}}
 +<WRAP centeralign>​
 +**图13-6 SRAM_IF读取时序**
 +</​WRAP>​
  
 +读控制信号bus_en和bus_rw为一个时钟周期的宽度,期间读地址bus_addr有效。在检测到读控制信号后,SRAM_IF将ce_i、oe_i、lb_i和ub_i置为有效,同时输出读地址。在两个时钟周期后读取data_i上的数据,并通过bus_dataout将数据输出给总线,同时置bus_dataready有效,宽度为一个时钟周期。在两个时钟周期后读取数据是因为SRAM读操作至少需要10ns,而时钟周期为10ns,一个周期不能保证读取操作完成,为保险起见,在两个时钟周期后读取数据。
 +
 +各接口信号由内部控制信号控制:
 +<code verilog> ​
 +
 +assign busy = reading | writing; ​ //​信号reading和writing为读、写操作标志信号,为高表示正在进行读操作或者写操作,任一操作都表示模块忙。
 + assign ce_i = !busy; ​ //​如果有读操作或写操作,则ce_i拉地,对SRAM使能。
 + assign oe_i = !reading; //​如果有读操作,则读控制信号oe_i有效。
 +assign we_i = !writing; //​如果有写操作,则写控制信号we_i有效。
 +assign lb_i = !busy; ​  
 +assign ub_i = !busy; ​  //​模块采用16位读写模式,所以lb_i和ub_i拉低表示16位读写。
 +
 +写操作由状态write_state控制,由3个状态组成:
 +always @(posedge clk or negedge reset ) begin : SRAM_writing
 + if(!reset) begin
 + writing <= 0;
 + write_state <= 0;
 + end
 + else begin
 + case( write_state )
 + 2'​d0:​ begin                       //​等待状态
 + if( bus_en && !bus_RW ) begin  //​表示写操作。
 + writing <= 1'​b1; ​         // 置写操作标识。
 + write_state <= 2'​b1; ​      //​状态转移。
 + end
 + end
 + 2'​d1:​ begin                       //​数据输出
 + write_state <= 2'​d2; ​          //​状态转移。
 + data_t <= bus_datain; ​         // 输出数据,​ data_i = data_t
 + end
 + 3'​d2:​ begin                      //​写操作完成。
 + write_state <= 2'​d0;​  ​ //​状态转移至等待状态。
 +
 + writing <= 1'​b0; ​             //​写操作标识清0。
 + data_t <= 16'​bzzzz_zzzz_zzzz_zzzz;​ //​将输出数据置为高阻。
 + end
 + endcase
 + end
 + end
 +
 +</​code>​
 +
 +
 +下面模块控制SRAM接口模块的地址线:
 +<code verilog> ​
 +
 +always @(posedge clk or negedge reset ) begin ​
 + if( !reset ) 
 + addr_i <= 0;
 + else ​
 + if( bus_en )              //​当读写控制使能时,输出地址线。
 + addr_i <= bus_addr;
 + end
 +读操作由状态机read_state控制,有四个状态:
 +always @(posedge clk or negedge reset ) begin : SRAM_reading
 + if(!reset) begin
 + reading <= 0;
 + bus_dataready <= 0;
 + bus_dataout <= 16'd0;
 + read_state <= 2'd0;
 + end
 + else begin
 + case( read_state )
 + 2'​d0:​ begin                              //​等待状态。
 + if( bus_en && bus_RW ) begin          //​检测到读操作。
 + reading <= 1'​b1; ​                //​读标识置位。
 + bus_dataout <= 16'​d0; ​           //​将总线输出清0。
 + read_state <= 2'​d1; ​              //​状态转移。
 + end
 + end
 + 2'​d1:​ begin                              //​读等待。
 + read_state <= 2'​d2; ​                   //​状态转移。
 + end
 +
 + 2'​d2:​ begin                             //​读取数据。
 + reading <= 1'​b0; ​                    // 复位读标识。
 + bus_dataout <= data_i; ​               //​读取数据并送给总线接口。
 + bus_dataready <= 1'​b1; ​            //​数据读取完成标识置位。
 + read_state <= 2'​d3; ​               //​状态转移。
 + end
 + 2'​d3:​ begin
 + bus_dataready <= 1'​b0; ​           //​数据读取完成标识清0。
 + read_state <= 2'​d0; ​              //​状态转移。
 + end
 + endcase
 + end
 + end
 +
 +</​code>​
 +
 +#### 3.3 SRAM_tester模块(SRAM_tester.v)
 +SRAM_ Tester模块完成对SRAM的扫描测试,对每一个地址写入一个数据并读取,检测写入和读取的是否一致。操作方式为:给地址A写入数据B(B为A的低16位);读取地址A-1中的数据B2,检测B2是否为A-1的低16位。读取地址A-1而不是A的原因是防止对A进行写操作时候在信号线的残留信号影响读取结果。
 +
 +SRAM_Tester的接口信号定义如下:
 +<code verilog> ​
 +
 +input reset, clk;​ //​时钟、复位信号。
 + input data_ready; ​ //​数据有效信号;在读取数据时,data_ready为高表示读取完成,data_in数据有效。
 + input [15:​0]data_in;​ //​读取操作时读取的数据,data_ready为高时有效。
 + output reg [15:0] data_out; //​写入操作时要写入的数据。
 + output reg [17:0] addr;    //​读取或写入的地址。
 + output reg enable; ​      //​使能信号,表示rw、addr、data_out有效。
 + output reg rw;          //​rw读写操作,为高时表示读操作,为低时表示写操作。
 + output reg data_right; ​   //​读写正确指示,为高时表示读取和写入的数据一致。
 +以上接口信号的时序如图13-5和图13-6所示。
 +由于时钟是100MHz,读写操作每2个时钟周期完成一次,因此定义50MHz的使能信号enable50M:
 +always @(posedge clk or negedge reset ) begin
 +if( !reset ) begin
 + enable50M <= 0;
 +end
 +else begin
 + enable50M <= ~enable50M;
 +end
 +end
 +
 +</​code>​
 +
 +扫描检测代码如下:
 +<code verilog> ​
 +
 +always @(posedge clk or negedge reset ) begin
 +if( !reset ) begin //​各信号复位。
 +enable <= 1'b0;
 +rw <= 1'b1;
 +state <= 2'​d0; ​       //​state为状态控制信号,有3个状态。
 +addr <= 18'd0;
 +data_out <= 0;
 +readaddr <= 0;
 +end 
 +else begin
 +if( enable )
 + enable <= 0;      //​当enable为高时,置enable为低,确保enable宽度为一个时钟周期。
 + if( enable50M ) begin   //​当enable50M为高时进行读写操作。
 + case( state )
 + 2'​d0:​ begin             //​进行写操作。
 + rw <= 0;
 + state <= 3'd1;
 + enable <= 1;
 +   end
 +
 + 2'​d1:​ begin              //​进行读操作。
 + rw <= 1;
 + enable <= 1;
 + addr <= addr - 16'​d1; ​ //​读取的地址为addr-1。
 + readaddr <= addr - 16'd1;
 + state <= 3'd2;
 + end
 +
 + 2'​d2:​ begin                  //​读取完成,准备下一轮写操作。
 + state <= 0;
 + addr <= addr + 16'​d2; ​ //​下一次读取的地址,由于在写入的时候减1了,所以要加2才是下一次写入的地址。
 + data_out <= data_out + 16'd1; //​下一次写入的数据。
 + enable <= 0;
 + end
 + default:
 + state <= 0;
 + endcase
 + end
 + end
 + end
 +
 +</​code>​
 +
 +read_comparison对读取的结果进行检测,看是否和写入的一致,读取值应为地址的低16位。当模块刚开始运行时,读取的地址为3FFFF,即最高地址位,但第一次运行时该地址中还未写入数据,无法进行比较。因此,定义信号first_read,复位时first_read为高,当first_read为高时不进行比较,并将first_read置0。之后便可以对结果进行比较:
 +<code verilog> ​
 +
 +always @(posedge clk or negedge reset ) begin : result_comparison
 + if( !reset ) begin
 +    ​first_read <= 1;
 + data_right <= 1;
 + end
 + else begin
 + if( data_ready ) begin
 +   if( first_read ) begin  //​当first_read为高时,不比较。
 +      ​first_read <= 0;
 +   end
 +   else if( data_in != readaddr[15:​0] )  //​对结果进行比较。
 + data_right <= 0;             //​如果结果错误,将data_right置0。
 + end
 + end
 + end
 +
 +</​code>​
 +
 +#### 3.4 LED_indicator模块(LED_indicator.v)
 +Led_indicator模块是根据检测结果来控制led灯,这个模块较为简单,不再详述。
  
 \\ \\
 \\ \\
-### 演示程序文件说明+### 4. 程序仿真 
 +SRAM_SIM(SRAM_SIM.v)是SRAM的仿真模块,用以模拟SRAM的行为,二维数组SRAMub和SRAMlb 分别用来模拟的SRAM的高8位和低8位,数组的长度可以自由设置,为了仿真方便设为10,也就是地址空间为0-9。由于核心板上的SRAM是异步SRAM,为了更真实地模拟SRAM的行为,采用组合逻辑加延时的方式来实现: 
 +<code verilog> ​
  
 +//​接口信号定义:
 +input ce,​oe,​we,​lb,​ub;  ​
 +input [17:0] addr;
 +inout wire [15:0] data;
  
 +//​用数组模拟存储器:
 +reg [7:0] SRAMub[10:​0];​
 +reg [7:0] SRAMlb[10:​0];​
 +
 +reg [15:0] data_t;
 +assign data = data_t;
 +
 +always@* begin
 +  case({ce,​oe,​we,​lb,​ub}) ​          //​对ce,​ oe, we, lb, ub几个信号进行判断。
 + 5'​b01000: ​                    //​对16位数据进行写操作。
 + begin ​
 + #5 SRAMub[addr] <= data[15:​8]; ​ //​这里加了5ns的延时,延时长短可以调整。
 + SRAMlb[addr] <= data[7:0];
 + end
 + 5'​b01010: ​                    //​对高8位数据进行写操作。
 + begin ​
 + #5 SRAMub[addr] <= data[15:8];
 + end
 + 5'​b01001: ​                   //​对低8位数据进行写操作。
 + begin
 + #5 SRAMlb[addr] <= data[7:0];
 + end
 + 5'​b00100: ​                    //​对16位数据进行读操作。
 + begin
 + #5 data_t[15:​8] <= SRAMub[addr];​
 + data_t[7:​0] <= SRAMlb[addr];​
 + end
 + 5'​b00110: ​                      //​对高8位数据进行读操作。
 + begin
 + #5 data_t[15:​8] <= SRAMub[addr];​
 + end
 + 5'​b00101: ​                      //​对低8位数据进行读操作。
 + begin
 + #5 data_t[7:0] <= SRAMlb[addr];​
 + end
 +
 + default: data_t <= 16'​bzzzz_zzzz_zzzz_zzzz; ​ //​其它情况下,数据线输出高阻。
 +        endcase
 +end
 +
 +</​code>​
 +
 +testtop是测试顶层模块,产生时钟和复位信号。
 +
 +仿真结果如图13-7所示,图中给出了一个完整的读写操作,写入地址是1,读取地址是0。
 +{{ :​图13-9.png |图13-7 SRAM仿真结果}}
 +<WRAP centeralign>​
 +**图13-7 SRAM仿真结果**
 +</​WRAP>​
 +
 +### 5. 运行结果
 +图13-8为将程序下载到开发系统后从SignalTap中观察到的实际运行结果。
 +{{ :​图13-10.png |图13-8 SRAM读写运行结果}}
 +<WRAP centeralign>​
 +**图13-8 SRAM读写运行结果**
 +</​WRAP>​
 +
 +从上图可以看出,从SRAM中读出的数和写入的一致。
 +
 +最后在实验板上的结果是只有right_light指示灯LED0缓慢地闪烁,验证了实验板上SRAM工作是正常的。
  
 \\ \\
 \\ \\
-### 演示程序使用+### 6. 演示程序文件说明 
 +|文件名|功能| 
 +|SRAM.v|顶层文件。| 
 +|SRAM_IF.v|SRAM_IF将SRAM的异步接口转换成同步接口。| 
 +|SRAM_Tester.v|SRAM_Tester是对SRAM进行测试,对每一个地址写入一个数据,同时读取该地址的数据,检测和写入的数据是否一致。| 
 +|SRAM_SIM.v|SRAM仿真模块,模拟SRAM的行为,用于对程序的仿真。| 
 +|Testtop.v|仿真顶层模块。| 
 +|SRAM_sim.mpf|ModelSim仿真项目。| 
 + 
 +\\ 
 +\\ 
 +### 7. 演示程序使用 
 +把程序下载到开发系统上后, sw1为复位端reset,可以看到LED0缓慢闪烁或LED7快速闪烁。LED0为right_light,​表示读写正确;LED7为error_light,​如从sram中读出的数据有误,则此灯快速闪烁。 
 + 
 + 
 + 
 +