在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

高級(jí)設(shè)計(jì):SDR SDRAM驅(qū)動(dòng)設(shè)計(jì)

FPGA技術(shù)江湖 ? 來(lái)源:FPGA技術(shù)江湖 ? 2024-01-19 15:47 ? 次閱讀

隨機(jī)訪問(wèn)存儲(chǔ)器(RAM)分為靜態(tài)RAM(SRAM)和動(dòng)態(tài)RAM(DRAM)。由于動(dòng)態(tài)存儲(chǔ)器存儲(chǔ)單元的結(jié)構(gòu)非常簡(jiǎn)單,所以它能達(dá)到的集成度遠(yuǎn)高于靜態(tài)存儲(chǔ)器。但是動(dòng)態(tài)存儲(chǔ)器的存取速度不如靜態(tài)存儲(chǔ)器快。

RAM的動(dòng)態(tài)存儲(chǔ)單元是利用電容可以存儲(chǔ)電荷的原理制成的。由于存儲(chǔ)單元的機(jī)構(gòu)能夠做得很簡(jiǎn)單,所以在大容量、高集成度的RAM中得到了普遍的應(yīng)用。但是由于電容的容量很小,而漏電流又不可能絕對(duì)等于零,所以電荷保存的時(shí)間有限。為了及時(shí)補(bǔ)充漏掉的電荷以避免存儲(chǔ)的信號(hào)丟失,必須定時(shí)地給電容補(bǔ)充電荷,通常將這種操作稱為刷新。

f35193b4-b69e-11ee-8b88-92fbcf53809c.png

行列地址線被選中后,數(shù)據(jù)線(data_bit)直接和電容相連接。當(dāng)寫入時(shí),數(shù)據(jù)線給電容充放電;讀取時(shí),電容將數(shù)據(jù)線拉高或者置低。

SDRAM 的全稱即同步動(dòng)態(tài)隨機(jī)存儲(chǔ)器(Synchronous Dynamic Random Access Memory);這里的同步是指其時(shí)鐘頻率與對(duì)應(yīng)控制器的系統(tǒng)時(shí)鐘頻率相同,并且內(nèi)部命令的發(fā)送與數(shù)據(jù)傳輸都是以該時(shí)鐘為基準(zhǔn);動(dòng)態(tài)是指存儲(chǔ)陣列需要不斷的刷新來(lái)保證數(shù)據(jù)不丟失。

SDR SDRAM中的SDR是指單數(shù)據(jù)速率,即每一根數(shù)據(jù)線上,每個(gè)時(shí)鐘只傳輸一個(gè)bit的數(shù)據(jù)。SDR SDRAM的時(shí)鐘頻率可以達(dá)到100MHz以上,按照100MHz的速率計(jì)算,一片16位數(shù)據(jù)寬度的SDR SDRAM的讀寫數(shù)據(jù)帶寬可以達(dá)到1.6Gbit/s。

SANXIN – B01的開發(fā)板上有一個(gè)容量為256Mbit(16M x 16bit)的SDR SDRAM(H57V2562GTR)。其內(nèi)部存儲(chǔ)時(shí),分為了4個(gè)獨(dú)立的區(qū)域(BANK),每個(gè)bank為4Mx16bit的存儲(chǔ)空間;每個(gè)bank在存儲(chǔ)時(shí),按照二維的方式進(jìn)行存儲(chǔ),利用行列來(lái)進(jìn)行確定,有8192行(13bit地址線),有512列(9bit地址線),8192 x 512為4M的存儲(chǔ)量。

在進(jìn)行指定某個(gè)地址時(shí),共需要2位bank地址,13位行地址,9位列地址,合計(jì)共24位地址。但是在SDR SDRAM的指定某個(gè)地址時(shí),行地址和列地址不是同時(shí)給出,SDR SDRAM采用行列地址線復(fù)用,所以地址線合計(jì)為2(bank 地址)+13(行、列地址復(fù)用)。

SDR SDRAM需要時(shí)鐘端和時(shí)鐘使能端。SDR SDRAM所有的操作都依靠于此時(shí)鐘;當(dāng)時(shí)鐘使能端無(wú)效時(shí),SDR SDRAM自動(dòng)忽略時(shí)鐘上升沿。

SDR SDRAM擁有四個(gè)命令控制線,分別為CS、RAS、CAS、WE。組成的命令表如下:

f356cba4-b69e-11ee-8b88-92fbcf53809c.png

在寫入數(shù)據(jù)時(shí),有時(shí)會(huì)出現(xiàn)不想對(duì)某8bit進(jìn)行寫入,就可以采用DQM進(jìn)行控制。

SDR SDRAM的內(nèi)部機(jī)構(gòu)為:

f3717fee-b69e-11ee-8b88-92fbcf53809c.png

由于SDR SDRAM為DRAM,內(nèi)部的存儲(chǔ)都是靠電容進(jìn)行保存數(shù)據(jù),電容的保持?jǐn)?shù)據(jù)的時(shí)間為64ms,SDR SDRAM每次只能夠刷新一行,為了不丟失任何數(shù)據(jù),所以要保證64ms內(nèi),將所有的行都要刷新一遍。

SDR SDRAM支持讀寫的長(zhǎng)度為1、2、4、8和一行(整頁(yè))。

具體的SDR SDRAM的介紹可以查看手冊(cè)。下面只介紹幾個(gè)相對(duì)重要的時(shí)序圖。

在SDR SDRAM正常使用之前,需要進(jìn)行初始化。初始化的時(shí)序圖如下:

f37c8e0c-b69e-11ee-8b88-92fbcf53809c.png

在PRECHARGE時(shí),A10為高,表示選中所有的bank;A10為低,表示選中BA0、BA1所指定的bank。初始化中,A10置高。

在LOAD MOOE REGISTER中,采用地址線進(jìn)行配置模式寄存器。說(shuō)明如下:

f38ff190-b69e-11ee-8b88-92fbcf53809c.png

在模式配置中,利用CL(CAS Latency)表示列選通潛伏期,利用BL(Burst Length)表示突發(fā)長(zhǎng)度。

SDR SDRAM中有內(nèi)部的刷新控制器和刷新的行計(jì)數(shù)器,外部控制器只需要保證在64ms之內(nèi)進(jìn)行8192次刷新即可。

在進(jìn)行PRECHARGE時(shí),A10要為高電平。

f3941536-b69e-11ee-8b88-92fbcf53809c.png

SDR SDRAM中,我們可以在任意位置進(jìn)行寫入。寫入的時(shí)序圖如下:

f39f09e6-b69e-11ee-8b88-92fbcf53809c.png

SDR SDRAM中,我們可以在任意位置進(jìn)行讀出。讀出的時(shí)序圖如下:

f3c0b910-b69e-11ee-8b88-92fbcf53809c.png

在各個(gè)時(shí)序中的時(shí)序參數(shù)如下:

f3c891da-b69e-11ee-8b88-92fbcf53809c.png

f3f92494-b69e-11ee-8b88-92fbcf53809c.png

設(shè)計(jì)要求

設(shè)計(jì)一個(gè)突發(fā)長(zhǎng)度為2,列選通潛伏期為2的SDR SDRAM的控制器。

設(shè)計(jì)分析

該控制器共有四部分功能,初始化、刷新、寫和讀。四部分的執(zhí)行控制采用一個(gè)模塊來(lái)控制。

SDR SDRAM必須要進(jìn)行初始化,初始化只用執(zhí)行一次。然后啟動(dòng)一個(gè)計(jì)時(shí)器,等計(jì)時(shí)器達(dá)到后,進(jìn)行刷新。在刷新的間隔中,根據(jù)讀寫的要求進(jìn)行讀寫。

四個(gè)模塊都會(huì)對(duì)SDR SDRAM的命令線和地址線進(jìn)行控制,所以輸出時(shí),采用多路選擇器對(duì)齊進(jìn)行選擇輸出。

四個(gè)模塊按照對(duì)應(yīng)的時(shí)序圖進(jìn)行編寫代碼即可。

架構(gòu)設(shè)計(jì)和信號(hào)說(shuō)明

該控制器命名為sdr_drive。

f3fd6324-b69e-11ee-8b88-92fbcf53809c.png

pll_sdr(鎖相環(huán)模塊):產(chǎn)生驅(qū)動(dòng)所需要的100MHz的時(shí)鐘(0度相位)、SDR SDRAM所需要的100MHz的時(shí)鐘(270度相位)、以及PLL鎖定信號(hào)當(dāng)作系統(tǒng)復(fù)位使用。

timer(刷新計(jì)時(shí)器):當(dāng)啟動(dòng)計(jì)時(shí)器后,開始計(jì)時(shí),當(dāng)計(jì)時(shí)到規(guī)定時(shí)間后,輸出刷新請(qǐng)求,計(jì)數(shù)器直接清零計(jì)數(shù)計(jì)數(shù)。當(dāng)控制器響應(yīng)后,輸出清除信號(hào)后,刷新請(qǐng)求拉低。

refresh(刷新模塊)、init(初始化模塊)、sdr_write(寫模塊)、sdr_read(讀模塊):當(dāng)啟動(dòng)模塊后,按照規(guī)定的時(shí)序進(jìn)行輸出即可,然后輸出完成信號(hào)。

sdr_ctrl(控制模塊):控制各個(gè)模塊協(xié)調(diào)工作。

mux4_1(四選一多路選擇器模塊):選擇對(duì)應(yīng)的bus總線作為輸出。

*_bus的組成為:高四位為sdr_cs_n、sdr_ras_n、sdr_cas_n、sdr_we_n。然后是bank的兩位,后續(xù)為13位的sdr_addr。

f408e71c-b69e-11ee-8b88-92fbcf53809c.png

f41b9f4c-b69e-11ee-8b88-92fbcf53809c.png

f41fa632-b69e-11ee-8b88-92fbcf53809c.png

sdr_drive_head聲明

將驅(qū)動(dòng)中用到各種參數(shù)定義在該文件中。

`defineSDR_ADDR_WIDTH13
`define       SDR_COL_ADDR_WIDTH                9
`define       SDR_REFRESH_TIME                  64_000_000


`define       ADDR_WIDTH   2 + `SDR_ADDR_WIDTH + `SDR_COL_ADDR_WIDTH
`define       BUS_WIDTH    4 + 2 + `SDR_ADDR_WIDTH


`define       CMD_INH                           4'b1000
`define       NOP                               4'b0111
`define       ACT                               4'b0011
`define       RD                                4'b0101
`define       WR                                4'b0100
`define       BT                                4'b0110
`define       PREC                              4'b0010
`define       REFR                              4'b0001
`define       LMR                               4'b0000


`define       PU_DELAY                          20_000
`define       Trp                               3
`define       Trfc                              7
`define       Tmrd                              3
`define       Trcd                              3
`define       Twr                               3
`define       Tcl                               2


`define       CODE                             13'b000_0_00_010_0_001
`define     REFRESH_TIME  (`SDR_REFRESH_TIME/(2**`SDR_ADDR_WIDTH))/10

pll_sdr設(shè)計(jì)實(shí)現(xiàn)

該模塊為IP core,輸出0相位的100MHz(系統(tǒng)時(shí)鐘)和270相位的100MHz(SDR的時(shí)鐘)。系統(tǒng)設(shè)計(jì)中,信號(hào)在上升沿輸出;對(duì)于外部器件(相位調(diào)整為270),能夠較好的滿足建立和保持時(shí)間。

init設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)將SDR SDRAM進(jìn)行初始化。上電延遲(PU_DELAY)設(shè)置為200us;預(yù)充電時(shí)間(Trp)設(shè)置為3個(gè)時(shí)鐘周期(30ns);自刷新時(shí)間(Trfc)設(shè)置為7個(gè)時(shí)鐘周期(70ns);模式寄存器應(yīng)用時(shí)間(Tmrd)設(shè)置為3個(gè)時(shí)鐘周期(30ns);突發(fā)長(zhǎng)度為2;列選通潛伏期為3。

按照對(duì)應(yīng)的初始化的時(shí)序圖,做出如下設(shè)計(jì)。

本模塊采用狀態(tài)機(jī)的方式設(shè)計(jì)實(shí)現(xiàn)。

f42d6dbc-b69e-11ee-8b88-92fbcf53809c.png

設(shè)計(jì)代碼為:

`include "../rtl/sdr_drive_head.v"


module init (


  input     wire                                  clk,
  input     wire                                  rst_n,


  input     wire                                  init_en,
  output    reg                                   init_done,


  output    wire        [`BUS_WIDTH - 1 : 0]      init_bus
);


  localparam      IDLE              =             7'b000_0001;
  localparam      PUD               =             7'b000_0010;
  localparam      PRECHARGE         =             7'b000_0100;
  localparam      AUTOREFR1         =             7'b000_1000;
  localparam      AUTOREFR2         =             7'b001_0000;
  localparam      LMR_STATE         =             7'b010_0000;
  localparam      INITDONE          =             7'b100_0000;


  reg                   [6:0]                     c_state;
  reg                   [6:0]                     n_state;
  wire                  [1:0]                     sdr_bank;
  reg                   [3:0]                     sdr_cmd;
  reg                   [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr;
  reg                   [14:0]                    cnt;                    


  assign sdr_bank = 2'b00;
  assign init_bus = {sdr_cmd,sdr_bank,sdr_addr};


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      c_state <= IDLE;
    else
      c_state <= n_state;
  end


  always @ * begin
    case (c_state)
      IDLE        :     begin
        if (init_en == 1'b1)
          n_state = PUD;
        else
          n_state = IDLE;
      end


      PUD         :     begin
        if (cnt == `PU_DELAY - 1'b1)
          n_state = PRECHARGE;
        else
          n_state = PUD;
      end


      PRECHARGE   :     begin
        if (cnt == `Trp - 1'b1)
          n_state = AUTOREFR1;
        else
          n_state = PRECHARGE;
      end


      AUTOREFR1   :     begin
        if (cnt == `Trfc - 1'b1)
          n_state = AUTOREFR2;
        else  
          n_state = AUTOREFR1;
      end


      AUTOREFR2   :     begin
        if (cnt == `Trfc - 1'b1)
          n_state = LMR_STATE;
        else  
          n_state = AUTOREFR2;
      end


      LMR_STATE   :     begin
        if (cnt == `Tmrd - 1'b1)
          n_state = INITDONE;
        else
          n_state = LMR_STATE;
      end


      INITDONE    :     begin
        n_state = INITDONE;
      end


      default     :   n_state = IDLE;
    endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_cmd <= `NOP;
    else
      case (c_state)
        IDLE        :   sdr_cmd <= `NOP;
        PUD         :   begin
          if (cnt == `PU_DELAY - 1'b1)
            sdr_cmd <= `PREC;
          else
            sdr_cmd <= `NOP;
        end
        PRECHARGE   :   begin
          if (cnt == `Trp - 1'b1)
            sdr_cmd <= `REFR;
          else
            sdr_cmd <= `NOP;
        end
        AUTOREFR1   :   begin
          if (cnt == `Trfc - 1'b1)
            sdr_cmd <= `REFR;
          else
            sdr_cmd <= `NOP;
        end
        AUTOREFR2   :   begin
          if (cnt == `Trfc - 1'b1)
            sdr_cmd <= `LMR;
          else
            sdr_cmd <= `NOP;
        end
        LMR_STATE   :   sdr_cmd <= `NOP;
        INITDONE    :   sdr_cmd <= `NOP;
        default     :   sdr_cmd <= `NOP;
      endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      cnt <= 15'd0;
    else
      case (c_state)
        IDLE        :   cnt <= 16'd0;
        PUD         :   begin
          if (cnt < `PU_DELAY - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 16'd0;
        end


        PRECHARGE    :   begin
          if (cnt < `Trp - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 16'd0;
        end
        AUTOREFR1    :   begin
          if (cnt < `Trfc - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 16'd0;
        end
        AUTOREFR2    :   begin
          if (cnt < `Trfc - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 16'd0;
        end
        LMR_STATE    :   begin
          if (cnt < `Tmrd - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 16'd0;
        end
        INITDONE    :   cnt <= 16'd0;
        default     :   cnt <= 16'd0;
      endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      init_done <= 1'b0;
    else
      if (c_state == LMR_STATE && cnt == `Tmrd - 1'b1)
        init_done <= 1'b1;
      else
        init_done <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_addr <= 0;
    else
      if (c_state == PUD && cnt == `PU_DELAY - 1'b1)
        sdr_addr[10] <= 1'b1;
      else
        if (c_state == AUTOREFR2 && cnt == `Trfc - 1'b1)
          sdr_addr <= `CODE;
        else
          sdr_addr <= 0;
  end


endmodule

timer設(shè)計(jì)實(shí)現(xiàn)

SDR SDRAM內(nèi)部構(gòu)造為DRAM,需要不間斷的刷新,要求64ms刷新一遍。每次刷新為一行,開發(fā)板上的SDR SDRAM共有8192行,平均需要7812.5ns刷新一次,我們選擇7810刷新一次。

到達(dá)規(guī)定的刷新時(shí)間時(shí),控制器有可能正在進(jìn)行其他的操作。在設(shè)計(jì)時(shí),達(dá)到時(shí)間后,發(fā)出刷新請(qǐng)求,當(dāng)外部執(zhí)行刷新后,將次請(qǐng)求清除。發(fā)出刷新請(qǐng)求的同時(shí),計(jì)數(shù)器重新歸零計(jì)數(shù)。

`include "../rtl/sdr_drive_head.v"


module timer (


  input   wire                    clk,
  input   wire                    rst_n,


  input   wire                    time_en,
  input   wire                    req_clr,


  output  reg                     refresh_req
);


  reg               [9:0]         cnt;


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      cnt <= 10'd0;
    else
      if (time_en == 1'b1 && cnt < `REFRESH_TIME - 1'b1)
        cnt <= cnt + 1'b1;
      else  
        cnt <= 10'd0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      refresh_req <= 1'b0;
    else
      if (cnt == `REFRESH_TIME - 1'b1)
        refresh_req <= 1'b1;
      else
        if (req_clr == 1'b1)
          refresh_req <= 1'b0;
        else
          refresh_req <= refresh_req;
  end


endmodule

refresh設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)刷新,按照對(duì)應(yīng)的時(shí)序圖進(jìn)行控制即可。

該模塊利用狀態(tài)機(jī)的方式實(shí)現(xiàn)。狀態(tài)轉(zhuǎn)移圖如下:

f4324954-b69e-11ee-8b88-92fbcf53809c.png

設(shè)計(jì)代碼為:

`include "../rtl/sdr_drive_head.v"


module refresh (


  input     wire                                  clk,
  input     wire                                  rst_n,


  input     wire                                  refresh_en,
  output    reg                                   refresh_done,


  output    wire        [`BUS_WIDTH - 1 : 0]      refresh_bus
);


  localparam      IDLE              =             5'b0_0001;
  localparam      PRECHARGE         =             5'b0_0010;
  localparam      AUTOREFR1         =             5'b0_0100;
  localparam      AUTOREFR2         =             5'b0_1000;
  localparam      REFRDONE          =             5'b1_0000;


  reg                   [4:0]                     c_state;
  reg                   [4:0]                     n_state;
  wire                  [1:0]                     sdr_bank;
  reg                   [3:0]                     sdr_cmd;
  reg                   [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr;
  reg                   [3:0]                     cnt;                    


  assign sdr_bank = 2'b00;
  assign refresh_bus = {sdr_cmd,sdr_bank,sdr_addr};


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      c_state <= IDLE;
    else
      c_state <= n_state;
  end


  always @ * begin
    case (c_state)
      IDLE        :     begin
        if (refresh_en == 1'b1)
          n_state = PRECHARGE;
        else
          n_state = IDLE;
      end


      PRECHARGE   :     begin
        if (cnt == `Trp - 1'b1)
          n_state = AUTOREFR1;
        else
          n_state = PRECHARGE;
      end


      AUTOREFR1   :     begin
        if (cnt == `Trfc - 1'b1)
          n_state = AUTOREFR2;
        else  
          n_state = AUTOREFR1;
      end


      AUTOREFR2   :     begin
        if (cnt == `Trfc - 1'b1)
          n_state = REFRDONE;
        else  
          n_state = AUTOREFR2;
      end


      REFRDONE    :     begin
        n_state = IDLE;
      end


      default     :   n_state = IDLE;
    endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_cmd <= `NOP;
    else
      case (c_state)
        IDLE        :   begin
          if (refresh_en == 1'b1)
            sdr_cmd <= `PREC;
          else
            sdr_cmd <= `NOP;
        end
        PRECHARGE   :   begin
          if (cnt == `Trp - 1'b1)
            sdr_cmd <= `REFR;
          else
            sdr_cmd <= `NOP;
        end
        AUTOREFR1   :   begin
          if (cnt == `Trfc - 1'b1)
            sdr_cmd <= `REFR;
          else
            sdr_cmd <= `NOP;
        end
        AUTOREFR2   :   sdr_cmd <= `NOP;


        REFRDONE    :   sdr_cmd <= `NOP;
        default     :   sdr_cmd <= `NOP;
      endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      cnt <= 4'd0;
    else
      case (c_state)
        IDLE        :   cnt <= 4'd0;


        PRECHARGE    :   begin
          if (cnt < `Trp - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 4'd0;
        end
        AUTOREFR1    :   begin
          if (cnt < `Trfc - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 4'd0;
        end
        AUTOREFR2    :   begin
          if (cnt < `Trfc - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 4'd0;
        end
        REFRDONE    :   cnt <= 4'd0;
        default     :   cnt <= 4'd0;
      endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      refresh_done <= 1'b0;
    else
      if (c_state == AUTOREFR2 && cnt == `Trfc - 1'b1)
        refresh_done <= 1'b1;
      else
        refresh_done <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_addr <= 0;
    else
      if (c_state == IDLE && refresh_en == 1'b1)
        sdr_addr[10] <= 1'b1;
      else
        sdr_addr <= 0;
  end


endmodule

sdr_write設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)將外部的數(shù)據(jù)寫入到規(guī)定的地址中去。在SDR SDRAM中,每操作(讀寫)一次,都會(huì)引起該存儲(chǔ)位的漏電,每次結(jié)束時(shí),可以進(jìn)行預(yù)充電。SDR SDRAM提供了自動(dòng)預(yù)充電的機(jī)制,在讀寫命令時(shí),sdr_addr[10]=1,即可自動(dòng)預(yù)充電。在設(shè)計(jì)時(shí),應(yīng)該要為自動(dòng)預(yù)充電預(yù)留出足夠的時(shí)間。

根據(jù)對(duì)應(yīng)的寫入時(shí)序圖,利用狀態(tài)機(jī)完成此設(shè)計(jì)。

f43de16a-b69e-11ee-8b88-92fbcf53809c.png

設(shè)計(jì)代碼如下:

`include "../rtl/sdr_drive_head.v"


module sdr_write (


  input     wire                            clk,
  input     wire                            rst_n,


  input     wire                            write_en,
  input     wire  [`ADDR_WIDTH - 1 : 0]     wr_addr,
  input     wire  [31:0]                    wr_data,


  output    reg   [15:0]                    odq,
  output    wire  [`BUS_WIDTH - 1 : 0]      wr_bus,
  output    reg                             wr_done
);


  localparam    IDLE            =           4'b0001;
  localparam    ACT_STATE       =           4'b0010;
  localparam    WR1             =           4'b0100;
  localparam    WR2             =           4'b1000;


  reg                   [3:0]                     c_state;
  reg                   [3:0]                     n_state;
  wire                  [1:0]                     sdr_bank;
  reg                   [3:0]                     sdr_cmd;
  reg                   [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr;
  reg                   [14:0]                    cnt;                    


  assign sdr_bank = wr_addr[23:22];
  assign wr_bus = {sdr_cmd,sdr_bank,sdr_addr};


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      c_state <= IDLE;
    else
      c_state <= n_state;
  end


  always @ * begin
    case (c_state)
      IDLE        :   begin
        if (write_en == 1'b1)
          n_state = ACT_STATE;
        else
          n_state = IDLE;
      end


      ACT_STATE   :   begin
        if (cnt == `Trcd - 1'b1)
          n_state = WR1;
        else
          n_state = ACT_STATE;
      end


      WR1         :    n_state = WR2;


      WR2         :   begin
        if (cnt == `Twr + `Trp - 1'b1)
          n_state = IDLE;
        else
          n_state = WR2;
      end


      default     :   n_state = IDLE;
    endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_cmd <= `NOP;
    else
      if (c_state == IDLE && write_en == 1'b1)
        sdr_cmd <= `ACT;
      else
        if (c_state == ACT_STATE && cnt == `Trcd - 1'b1)
          sdr_cmd <= `WR;
        else
          sdr_cmd <= `NOP;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_addr <= 0;
    else
      if (c_state == IDLE && write_en == 1'b1)
        sdr_addr <= wr_addr[21:9];
      else
        if (c_state == ACT_STATE && cnt == `Trcd - 1'b1) begin
          sdr_addr[10] <= 1'b1;
          sdr_addr[8:0] <= wr_addr[8:0];
        end
        else
          sdr_addr <= 0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      cnt <= 4'd0;
    else
      if (c_state == ACT_STATE && cnt < `Trcd - 1'b1)
        cnt <= cnt + 1'b1;
      else
        if (c_state == WR2 && cnt < `Twr + `Trp - 1'b1)
          cnt <= cnt + 1'b1;
        else
          cnt <= 4'd0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      odq <= 16'd0;
    else
      if (c_state == ACT_STATE && cnt == `Trcd - 1'b1)
        odq <= wr_data[15:0];
      else
        if (c_state == WR1)
          odq <= wr_data[31:16];
        else
          odq <= 16'd0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      wr_done <= 1'b0;
    else
      if (c_state == WR2 && cnt < `Twr + `Trp - 1'b1)
        wr_done <= 1'b1;
      else
        wr_done <= 1'b0;
  end


endmodule

sdr_read設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)從指定的地址中,將數(shù)據(jù)讀出。

按照對(duì)應(yīng)的讀時(shí)序圖即可實(shí)現(xiàn)功能,本模塊采用狀態(tài)機(jī)方式實(shí)現(xiàn),狀態(tài)轉(zhuǎn)移圖如下:

f44fe856-b69e-11ee-8b88-92fbcf53809c.png

設(shè)計(jì)代碼為:

module sdr_read (


  input   wire                              clk,
  input   wire                              rst_n,


  input   wire                              read_en,
  input   wire    [`ADDR_WIDTH - 1 : 0]     rd_addr,


  input   wire    [15:0]                    sdr_dq,


  output  reg     [31:0]                    rd_data,
  output  reg                               rd_done,


  output  wire    [`BUS_WIDTH - 1 : 0]      rd_bus
);


  localparam    IDLE            =           5'b00001;
  localparam    ACT_STATE       =           5'b00010;
  localparam    READ_STATE      =           5'b00100;
  localparam    RD1             =           5'b01000;
  localparam    RD2             =           5'b10000;


  reg                   [4:0]                     c_state;
  reg                   [4:0]                     n_state;
  wire                  [1:0]                     sdr_bank;
  reg                   [3:0]                     sdr_cmd;
  reg                   [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr;
  reg                   [3:0]                     cnt;                    


  assign sdr_bank = rd_addr[23:22];
  assign rd_bus = {sdr_cmd,sdr_bank,sdr_addr};


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      c_state <= IDLE;
    else
      c_state <= n_state;
  end


  always @ * begin
    case (c_state)
      IDLE        :   begin
        if (read_en == 1'b1)
          n_state = ACT_STATE;
        else
          n_state = IDLE;
      end


      ACT_STATE   :   begin
        if (cnt == `Trcd - 1'b1)
          n_state = READ_STATE;
        else
          n_state = ACT_STATE;
      end


      READ_STATE  :   begin
        if (cnt == `Tcl)
          n_state = RD1;
        else
          n_state = READ_STATE;
      end


      RD1         :   n_state = RD2;


      RD2         :   begin
        if (cnt == `Trp - 1'b1)
          n_state = IDLE;
        else
          n_state = RD2;
      end


      default     :   n_state = IDLE;
    endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_cmd <= `NOP;
    else
      if (c_state == IDLE && read_en == 1'b1)
        sdr_cmd <= `ACT;
      else
        if (c_state == ACT_STATE && cnt == `Trcd - 1'b1)
          sdr_cmd <= `RD;
        else
          sdr_cmd <= `NOP;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      sdr_addr <= 0;
    else
      if (c_state == IDLE && read_en == 1'b1)
        sdr_addr <= rd_addr[21:9];
      else
        if (c_state == ACT_STATE && cnt == `Trcd - 1'b1) begin
          sdr_addr[10] <= 1'b1;
          sdr_addr[8:0] <= rd_addr[8:0];
        end
        else
          sdr_addr <= 0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      cnt <= 4'd0;
    else
      case (c_state)
        IDLE      :     cnt <= 4'd0;
        ACT_STATE :     begin
          if (cnt < `Trcd - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 4'd0;
        end
        READ_STATE:     begin
          if (cnt < `Tcl)
            cnt <= cnt + 1'b1;
          else
            cnt <= 4'd0;
        end


        RD1       :     cnt <= 4'd0;
        RD2       :     begin
          if (cnt < `Trp - 1'b1)
            cnt <= cnt + 1'b1;
          else
            cnt <= 4'd0;
        end
        default   :     cnt <= 4'd0;
      endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rd_data <= 32'd0;
    else
      if (c_state == READ_STATE && cnt == `Tcl)
        rd_data[15:0] <= sdr_dq;
      else
        if (c_state == RD1)
          rd_data[31:16] <= sdr_dq;
        else
          rd_data <= rd_data;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rd_done <= 1'b0;
    else
      if (c_state == RD2 && cnt < `Trp - 1'b1)
        rd_done <= 1'b1;
      else
        rd_done <= 1'b0;
  end


endmodule

mux4_1設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)選擇出對(duì)應(yīng)的bus,然后將對(duì)應(yīng)位作為輸出即可。

設(shè)計(jì)代碼為:

module mux4_1 (


  input   wire  [`BUS_WIDTH - 1 : 0]      init_bus,
  input   wire  [`BUS_WIDTH - 1 : 0]      refresh_bus,
  input   wire  [`BUS_WIDTH - 1 : 0]      wr_bus,
  input   wire  [`BUS_WIDTH - 1 : 0]      rd_bus,
  input   wire  [1:0]                     mux_sel,


  output  wire  [1 : 0]                   sdr_bank,
  output  wire  [`ADDR_WIDTH - 1 : 0]     sdr_addr,
  output  wire                            sdr_cs_n,
  output  wire                            sdr_ras_n,
  output  wire                            sdr_cas_n,
  output  wire                            sdr_we_n
);


  reg           [`BUS_WIDTH - 1 : 0]      sdr_bus;


  assign sdr_cs_n = sdr_bus[18];
  assign sdr_ras_n = sdr_bus[17];
  assign sdr_cas_n = sdr_bus[16];
  assign sdr_we_n = sdr_bus[15];


  assign sdr_bank = sdr_bus[14:13];


  assign sdr_addr = sdr_bus[12:0];


  always @ * begin
    case (mux_sel)
      2'b00       :   sdr_bus = init_bus;
      2'b01       :   sdr_bus = refresh_bus;
      2'b10       :   sdr_bus = wr_bus;
      2'b11       :   sdr_bus = rd_bus;
      default     :   sdr_bus = init_bus;
    endcase
  end


endmodule

sdr_ctrl設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)調(diào)度整個(gè)控制器,利用狀態(tài)機(jī)實(shí)現(xiàn)。

f454e14e-b69e-11ee-8b88-92fbcf53809c.png

設(shè)計(jì)代碼為:

`include "../rtl/sdr_drive_head.v"


module sdr_ctrl (


  input   wire                          clk,
  input   wire                          rst_n,


  input   wire                          wr_en,
  input   wire                          rd_en,
  input   wire    [`ADDR_WIDTH - 1 : 0] addr,
  input   wire    [31:0]                wdata,
  output  reg     [31:0]                rdata,
  output  reg                           rd_valid,


  output  wire                          sdr_busy,


  output  reg     [1:0]                 mux_sel,


  output  reg                           init_en,
  input   wire                          init_done,


  output  reg                           time_en,
  input   wire                          refresh_req,
  output  reg                           req_clr,


  output  reg                           refresh_en,
  input   wire                          refresh_done,


  output  reg                           out_en,
  output  reg                           write_en,
  output  reg     [`ADDR_WIDTH - 1 : 0] wr_addr,
  output  reg     [31:0]                wr_data,
  input   wire                          wr_done,


  output  reg                           read_en,
  output  reg     [`ADDR_WIDTH - 1 : 0] rd_addr,
  input   wire    [31:0]                rd_data,
  input   wire                          rd_done
);


  localparam      IDLE            =     6'b000_001;
  localparam      INIT_STATE      =     6'b000_010;
  localparam      REFRESH_STATE   =     6'b000_100;
  localparam      NO_BUSY         =     6'b001_000;
  localparam      WR_STATE        =     6'b010_000;
  localparam      RD_STATE        =     6'b100_000;


  reg             [5:0]                 c_state;
  reg             [5:0]                 n_state;
  reg                                   wren;
  reg                                   wren_clr;
  reg                                   rden;
  reg                                   rden_clr;
  reg             [`ADDR_WIDTH - 1 : 0] addrr;
  reg             [31:0]                wdatar;
  reg                                   busy;


  assign sdr_busy = busy | rd_en | wr_en;


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      wren <= 1'b0;
    else
      if (wr_en == 1'b1)
        wren <= 1'b1;
      else
        if (wren_clr == 1'b1)
          wren <= 1'b0;
        else
          wren <= wren;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rden <= 1'b0;
    else
      if (rd_en == 1'b1)
        rden <= 1'b1;
      else
        if (rden_clr == 1'b1)
          rden <= 1'b0;
        else
          rden <= rden;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      wdatar <= 32'd0;
    else
      if (wr_en == 1'b1)
        wdatar <= wdata;
      else
        wdatar <= wdatar;
  end 


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      addrr <= 0;
    else
      if (wr_en == 1'b1 || rd_en == 1'b1)
        addrr <= addr;
      else
        addrr <= addrr;
  end 


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      c_state <= IDLE;
    else
      c_state <= n_state;
  end


  always @ * begin
    case (c_state)
      IDLE              :   n_state = INIT_STATE;


      INIT_STATE        :   begin
        if (init_done == 1'b1)
          n_state = REFRESH_STATE;
        else
          n_state = INIT_STATE;
      end


      REFRESH_STATE     :   begin
        if (refresh_done == 1'b1)
          n_state = NO_BUSY;
        else
          n_state = REFRESH_STATE;
      end


      NO_BUSY           :   begin
        if (refresh_req == 1'b1)
          n_state = REFRESH_STATE;
        else
          if (wren == 1'b1)
            n_state = WR_STATE;
          else
            if (rden == 1'b1)
              n_state = RD_STATE;
            else
              n_state = NO_BUSY;
      end


      WR_STATE          :   begin
        if (wr_done == 1'b1)
          n_state = NO_BUSY;
        else
          n_state = WR_STATE;
      end


      RD_STATE          :   begin
        if (rd_done == 1'b1)
          n_state = NO_BUSY;
        else
          n_state = RD_STATE;
      end


      default           :   n_state = IDLE;
    endcase
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      busy <= 1'b1;
    else
      if (c_state == NO_BUSY && wren == 1'b0 && rden == 1'b0 && refresh_req == 1'b0)
        busy <= rd_en | wr_en;
      else
        busy <= 1'b1;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      init_en <= 1'b0;
    else
      if (c_state == IDLE)
        init_en <= 1'b1;
      else
        init_en <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      time_en <= 1'b0;
    else
      if (c_state == INIT_STATE && init_done == 1'b1)
        time_en <= 1'b1;
      else
        time_en <= time_en;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      refresh_en <= 1'b0;
    else
      if (c_state == INIT_STATE && init_done == 1'b1)
        refresh_en <= 1'b1;
      else
        if (c_state == NO_BUSY && refresh_req == 1'b1)
          refresh_en <= 1'b1;
        else
          refresh_en <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      req_clr <= 1'b0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b1)
        req_clr <= 1'b1;
      else
        req_clr <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      write_en <= 1'b0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b1)
        write_en <= 1'b1;
     else
        write_en <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      out_en <= 1'b0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b1)
        out_en <= 1'b1;
     else
        if (c_state == WR_STATE && wr_done == 1'b1)
          out_en <= 1'b0;
        else
          out_en <= out_en;
  end 


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      wr_addr <= 0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b1)
        wr_addr <= addrr;
     else
        wr_addr <= wr_addr;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      wr_data <= 0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b1)
        wr_data <= wdatar;
     else
        wr_data <= wr_data;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      wren_clr <= 1'b0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b1)
        wren_clr <= 1'b1;
     else
        wren_clr <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rden_clr <= 1'b0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b0 && rden == 1'b1)
        rden_clr <= 1'b1;
     else
        rden_clr <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      read_en <= 1'b0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b0 && rden == 1'b1)
        read_en <= 1'b1;
     else
        read_en <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rd_addr <= 0;
    else
      if (c_state == NO_BUSY && refresh_req == 1'b0 && wren == 1'b0 && rden == 1'b1)
        rd_addr <= addrr;
     else
        rd_addr <= rd_addr;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rdata <= 32'd0;
    else
      if (c_state == RD_STATE && rd_done == 1'b1)
        rdata <= rd_data;
      else
        rdata <= rdata;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rd_valid <= 1'b0;
    else
      if (c_state == RD_STATE && rd_done == 1'b1)
        rd_valid <= 1'b1;
      else
        rd_valid <= 1'b0;
  end 


  always @ (posedge clk, negedge rst_n)  begin
    if (rst_n == 1'b0)
      mux_sel <= 2'b00;
    else
      case (c_state)
        IDLE        :       mux_sel <= 2'b00;
        INIT_STATE  :       begin
          if (init_done == 1'b1)
            mux_sel <= 2'b01;
          else  
            mux_sel <= mux_sel;
        end
        REFRESH_STATE:      mux_sel <= mux_sel;
        NO_BUSY     :       begin
          if (refresh_req == 1'b1)
            mux_sel <= 2'b01;
          else
            if (wren == 1'b1)
              mux_sel <= 2'b10;
            else
              if (rden == 1'b1)
                mux_sel <= 2'b11;
              else
                mux_sel <= mux_sel;
        end
        RD_STATE    :   mux_sel <= mux_sel;
        WR_STATE    :   mux_sel <= mux_sel;


        default     :   mux_sel <= 2'b00;
      endcase
  end


endmodule

為了防止在進(jìn)行刷新的起始部分丟失讀寫命令,所以在設(shè)計(jì)時(shí),加入了緩存結(jié)構(gòu),只要有讀寫命令時(shí),都會(huì)進(jìn)行保存。在讀寫執(zhí)行時(shí),才會(huì)清除此命令。

RTL仿真

為了能夠仿真此設(shè)計(jì),需要用到SDR SDRAM的仿真模型。仿真模型在msim的sdr_sim_module中,將其修改為行線為13bit,列為9bit,每個(gè)bank有4194304個(gè)存儲(chǔ)空間。

f45e919e-b69e-11ee-8b88-92fbcf53809c.png

在仿真時(shí),在第二個(gè)bank,第五行,第10列,寫入一個(gè)隨機(jī)值。然后讀取出來(lái)。

仿真代碼為:

`timescale 1ns/1ps


module sdr_drive_tb;


  reg                     clk;
  reg                     rst_n;


  wire                    sys_clk;
  wire                    sys_rst_n;


  wire                    sdr_busy;
  reg                     wr_en;
  reg                     rd_en;
  reg       [23:0]        addr;
  reg       [31:0]        wdata;
  wire      [31:0]        rdata;
  wire                    rd_valid;


  wire                    sdr_clk;
  wire                    sdr_cke;
  wire                    sdr_cs_n;
  wire                    sdr_ras_n;
  wire                    sdr_cas_n;
  wire                    sdr_we_n;
  wire      [15:0]        sdr_dq;
  wire      [1:0]         sdr_bank;
  wire      [1:0]         sdr_dqm;
  wire      [12:0]        sdr_addr;


  sdr_drive sdr_drive_inst(


      .clk                  (clk),
      .rst_n                (rst_n),


      .sys_clk              (sys_clk),
      .sys_rst_n            (sys_rst_n),


    //  local
      .sdr_busy             (sdr_busy),
      .wr_en                (wr_en),
      .rd_en                (rd_en),
      .addr                 (addr),
      .wdata                (wdata),
      .rdata                (rdata),
      .rd_valid             (rd_valid),


    //  sdr
      .sdr_clk              (sdr_clk),
      .sdr_cke              (sdr_cke),
      .sdr_cs_n             (sdr_cs_n),
      .sdr_ras_n            (sdr_ras_n),
      .sdr_cas_n            (sdr_cas_n),
      .sdr_we_n             (sdr_we_n),
      .sdr_bank             (sdr_bank),
      .sdr_addr             (sdr_addr),
      .sdr_dqm              (sdr_dqm),
      .sdr_dq               (sdr_dq)
    );


  mt48lc32m16a2 mt48lc32m16a2_inst(
      .Dq                   (sdr_dq), 
      .Addr                 (sdr_addr), 
      .Ba                   (sdr_bank), 
      .Clk                  (sdr_clk), 
      .Cke                  (sdr_cke), 
      .Cs_n                 (sdr_cs_n), 
      .Ras_n                (sdr_ras_n), 
      .Cas_n                (sdr_cas_n), 
      .We_n                 (sdr_we_n), 
      .Dqm                  (sdr_dqm)
    );


  initial clk = 1'b0;
  always # 10 clk = ~clk;


  initial begin
    rst_n = 1'b0;
    wr_en = 1'b0;
    rd_en = 1'b0;
    addr = {2'b01, 13'd5,9'd10};
    wdata = 32'd0;
    # 201
    rst_n = 1'b1;
    @ (negedge sdr_busy);
    @ (posedge sys_clk);
    # 2;
    wr_en = 1'b1;
    wdata = $random;
    @ (posedge sys_clk);
    # 2;
    wr_en = 1'b0;
    # 2000;
    @ (negedge sdr_busy);
    @ (posedge sys_clk);
    # 2;
    rd_en = 1'b1;
    @ (posedge sys_clk);
    # 2;
    rd_en = 1'b0;
    # 2000;
    $stop;
  end


endmodule

這設(shè)置激勵(lì)時(shí),將tb文件和仿真模型文件同時(shí)加入添加文件中。

f462c9c6-b69e-11ee-8b88-92fbcf53809c.png

在modelsim的報(bào)告界面會(huì)顯示出具體的配置信息以及讀寫信息。

f468cc54-b69e-11ee-8b88-92fbcf53809c.png

從打印的報(bào)告中可以看出,在初始化時(shí),列選通潛伏期為2,突發(fā)長(zhǎng)度為2。在后續(xù)的讀寫時(shí),在指定的位置,寫入了13604,后續(xù)的一個(gè)位置為4629;在讀出時(shí),也正確的讀出了數(shù)據(jù)。

報(bào)告打印出寫入數(shù)據(jù),即認(rèn)為寫入成功;報(bào)告打印出讀出數(shù)據(jù),只能證明控制器將數(shù)據(jù)讀出,并不表示控制器能把數(shù)據(jù)接收到。

f47b663e-b69e-11ee-8b88-92fbcf53809c.png

通過(guò)控制輸出的rdata以及對(duì)應(yīng)的rd_valid信號(hào),確定讀出成功。在rdata中顯示為16進(jìn)制,16進(jìn)制的1215為十進(jìn)制的4629;16進(jìn)制的3524的為十進(jìn)制的13604。證明讀數(shù)據(jù)接收正確。

板級(jí)測(cè)試

編寫控制器的上游模塊(sdr_drive_test_crtl),控制寫入和讀出。在固定的地址中addr = {2'b01, 13'd128, 9'd20},寫入一個(gè)固定的數(shù)字wdata = 32'h5a5aa5a5,然后讀出,進(jìn)行驗(yàn)證。

讀者在進(jìn)行驗(yàn)證時(shí),可以采樣其他的地址或者數(shù)據(jù)進(jìn)行驗(yàn)證,且可以進(jìn)行多次嘗試,保證設(shè)計(jì)正確。

該模塊采用狀態(tài)機(jī)設(shè)計(jì)實(shí)現(xiàn)。

f485f914-b69e-11ee-8b88-92fbcf53809c.png

設(shè)計(jì)代碼為:

`include "../rtl/sdr_drive_head.v"


module sdr_drive_test_ctrl (


  input     wire                                    clk,
  input     wire                                    rst_n,


  input     wire                                    sdr_busy,
  output    reg                                     wr_en,
  output    reg                                     rd_en,
  output    wire      [31:0]                        wdata,
  input     wire                                    rd_valid,
  input     wire      [31:0]                        rdata,
  output    wire      [`ADDR_WIDTH - 1 : 0]         addr
);


  localparam          IDLE        =   4'b0001;
  localparam          WR_STATE    =   4'b0010;
  localparam          RD_STATE    =   4'b0100;
  localparam          TEST_DONE   =   4'b1000;


  reg                 [3:0]         c_state;
  reg                 [3:0]         n_state;


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      c_state <= IDLE;
    else
      c_state <= n_state;
  end


  always @ * begin
    case (c_state)
      IDLE          :   begin
        if (sdr_busy == 1'b0)
          n_state = WR_STATE;
        else
          n_state = IDLE;
      end


      WR_STATE      :   begin
        if (sdr_busy == 1'b0)
          n_state = RD_STATE;
        else
          n_state = WR_STATE;
      end


      RD_STATE      :   begin
        if (rd_valid == 1'b1 && rdata == 32'h5a5aa5a5)
          n_state = TEST_DONE;
        else
          n_state = RD_STATE;
      end


      TEST_DONE     :   n_state = TEST_DONE;




      default       :   n_state = IDLE;
    endcase
  end


  assign wdata = 32'h5a5aa5a5;
  assign addr = {2'b01, 13'd128, 9'd20};


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      wr_en <= 1'b0;
    else
      if (c_state == IDLE && sdr_busy == 1'b0)
        wr_en <= 1'b1;
      else
        wr_en <= 1'b0;
  end


  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      rd_en <= 1'b0;
    else
      if (c_state == WR_STATE && sdr_busy == 1'b0)
        rd_en <= 1'b1;
      else
        rd_en <= 1'b0;
  end


endmodule

編寫測(cè)試頂層,模塊命名為sdr_drive_test,并且設(shè)置為頂層。

此模塊負(fù)責(zé)例化sdr_drive和sdr_drive_test_ctrl,完成連接功能,以此測(cè)試。

代碼為:

`include "../rtl/sdr_drive_head.v"


module sdr_drive_test (


  input     wire                                    clk,
  input     wire                                    rst_n,


//  sdr
  output    wire                                    sdr_clk,
  output    wire                                    sdr_cke,
  output    wire                                    sdr_cs_n,
  output    wire                                    sdr_ras_n,
  output    wire                                    sdr_cas_n,
  output    wire                                    sdr_we_n,
  output    wire      [1:0]                         sdr_bank,
  output    wire      [`SDR_ADDR_WIDTH - 1 : 0]     sdr_addr,
  output    wire      [1:0]                         sdr_dqm,
  inout     wire      [15:0]                        sdr_dq
);


  wire                                    sys_clk;
  wire                                    sys_rst_n;


//  local
  wire                                    sdr_busy;
  wire                                    wr_en;
  wire                                    rd_en;
  wire      [`ADDR_WIDTH - 1 : 0]         addr;
  wire      [31:0]                        wdata;
  wire      [31:0]                        rdata;
  wire                                    rd_valid;


  sdr_drive_test_ctrl sdr_drive_test_ctrl_inst(


      .clk                (sys_clk),
      .rst_n              (sys_rst_n),


      .sdr_busy           (sdr_busy),
      .wr_en              (wr_en),
      .rd_en              (rd_en),
      .wdata              (wdata),
      .rd_valid           (rd_valid),
      .rdata              (rdata),
      .addr               (addr)
    );


  sdr_drive sdr_drive_inst(


      .clk                (clk),
      .rst_n              (rst_n),


      .sys_clk            (sys_clk),
      .sys_rst_n          (sys_rst_n),


    //  local
      .sdr_busy           (sdr_busy),
      .wr_en              (wr_en),
      .rd_en              (rd_en),
      .addr               (addr),
      .wdata              (wdata),
      .rdata              (rdata),
      .rd_valid           (rd_valid),


    //  sdr
      .sdr_clk            (sdr_clk),
      .sdr_cke            (sdr_cke),
      .sdr_cs_n           (sdr_cs_n),
      .sdr_ras_n          (sdr_ras_n),
      .sdr_cas_n          (sdr_cas_n),
      .sdr_we_n           (sdr_we_n),
      .sdr_bank           (sdr_bank),
      .sdr_addr           (sdr_addr),
      .sdr_dqm            (sdr_dqm),
      .sdr_dq             (sdr_dq)
    );


endmodule

經(jīng)過(guò)綜合分析后,進(jìn)行分配管腳。在分配管腳后,需要將雙功能管腳中的NCEO設(shè)置為普通用戶IO。如果不設(shè)置,將會(huì)出現(xiàn)如下錯(cuò)誤:

f48fba62-b69e-11ee-8b88-92fbcf53809c.png

右擊器件名稱,選擇DEVICE。

f494d31c-b69e-11ee-8b88-92fbcf53809c.png

選擇device and pin option。

f498afd2-b69e-11ee-8b88-92fbcf53809c.png

選擇dual – purpose pins。

f4acc170-b69e-11ee-8b88-92fbcf53809c.png

將nceo設(shè)置為 use as regular IO。

f4b1096a-b69e-11ee-8b88-92fbcf53809c.png

點(diǎn)擊OK,進(jìn)行編譯即可。

連接上開發(fā)板,啟動(dòng)邏輯分析儀。

將采樣時(shí)鐘選擇為,sys_clk(PLL的c0)。采樣深度選擇為1K。

f4c1ffcc-b69e-11ee-8b88-92fbcf53809c.png

添加觀測(cè)信號(hào)如下,將wr_en的上升沿設(shè)置為觸發(fā)條件。

f4c5ccce-b69e-11ee-8b88-92fbcf53809c.png

經(jīng)過(guò)保存,重新形成配置文件后,進(jìn)行下板測(cè)試。

下板后,按下復(fù)位。等待波形觸發(fā)。

f4c9ab0a-b69e-11ee-8b88-92fbcf53809c.png

通過(guò)邏輯分析儀,就可以看出可以正確的寫入和讀出數(shù)據(jù)。

讀者也可以進(jìn)行嘗試一次性寫入多個(gè)數(shù)據(jù),然后進(jìn)行讀出,進(jìn)行驗(yàn)證設(shè)計(jì)的正確性。







審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • SDRAM
    +關(guān)注

    關(guān)注

    7

    文章

    423

    瀏覽量

    55228
  • 存儲(chǔ)器
    +關(guān)注

    關(guān)注

    38

    文章

    7492

    瀏覽量

    163845
  • RAM
    RAM
    +關(guān)注

    關(guān)注

    8

    文章

    1368

    瀏覽量

    114704
  • SDR
    SDR
    +關(guān)注

    關(guān)注

    7

    文章

    233

    瀏覽量

    50485
  • 邏輯分析儀
    +關(guān)注

    關(guān)注

    3

    文章

    214

    瀏覽量

    23172

原文標(biāo)題:FPGA零基礎(chǔ)學(xué)習(xí)精選 | SDR SDRAM 驅(qū)動(dòng)設(shè)計(jì)

文章出處:【微信號(hào):HXSLH1010101010,微信公眾號(hào):FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    SDR SDRAM 為例,DRAM Device 與 Host 端的接口描述

    本文則以 SDR SDRAM 為例,描述 DRAM Device 與 Host 端的接口,以及其內(nèi)部的其他模塊,包括 Control Logic、IO、Row & Column Decoder 等。
    的頭像 發(fā)表于 09-22 15:34 ?4814次閱讀
    以<b class='flag-5'>SDR</b> <b class='flag-5'>SDRAM</b> 為例,DRAM Device 與 Host 端的接口描述

    詳解:SDR/DDR/DDR2/SDRAM的功能及異同

    (不好意思,說(shuō)得有點(diǎn)絕對(duì)了~-~)。SDRAMSDR到DDR再到DDR2一路走來(lái),又都產(chǎn)生了什么樣的變化,又都在哪些方面進(jìn)行了改進(jìn),帶來(lái)了速度性能的進(jìn)一步提升呢?帶著這個(gè)疑問(wèn)搜索了一些資料,也分別找來(lái)SDR
    發(fā)表于 12-30 15:22

    Spartan 6是否支持SDR SDRAM

    嗨,Spartan 6是否支持SDR SDRAM(單數(shù)據(jù)輻射SDRAM)?在ISE存儲(chǔ)器接口生成器中,沒(méi)有選擇SDR SDRAM的選項(xiàng)。有沒(méi)
    發(fā)表于 04-16 09:33

    高級(jí)RF收發(fā)器滿足SDR應(yīng)用的需求是什么?

    高級(jí)RF收發(fā)器滿足SDR應(yīng)用的需求是什么?
    發(fā)表于 05-19 06:51

    講解SDRAM驅(qū)動(dòng)實(shí)現(xiàn) 精選資料分享

    第49章 STM32H7的FMC總線應(yīng)用之SDRAM本章教程為大家講解SDRAM驅(qū)動(dòng)實(shí)現(xiàn),后面LCD的顯存和大數(shù)量的存取都要用到。49.1 初學(xué)者重要提示49.2 SDRAM硬件設(shè)計(jì)
    發(fā)表于 08-13 08:09

    FPGA零基礎(chǔ)學(xué)習(xí):SDR SDRAM 驅(qū)動(dòng)設(shè)計(jì)

    不多說(shuō),上貨。 高級(jí)設(shè)計(jì):SDR SDRAM 驅(qū)動(dòng)設(shè)計(jì) 本篇實(shí)現(xiàn)基于叁芯智能科技的SANXIN -B01 FPGA開發(fā)板,以下為配套的教程,如有入手開發(fā)板,可以登錄官方淘寶店購(gòu)買,還有
    發(fā)表于 03-23 17:40

    FPGA零基礎(chǔ)學(xué)習(xí):SDR SDRAM驅(qū)動(dòng)設(shè)計(jì)實(shí)用進(jìn)階

    實(shí)戰(zhàn)應(yīng)用,這種快樂(lè)試試你就會(huì)懂的。話不多說(shuō),上貨。SDR SDRAM驅(qū)動(dòng)設(shè)計(jì)實(shí)用進(jìn)階 本篇實(shí)現(xiàn)基于叁芯智能科技的SANXIN -B01 FPGA開發(fā)板,以下為配套的教程,如有入手開發(fā)板,可以登錄官方
    發(fā)表于 03-27 17:09

    AMBA DDR、LPDDR和SDR動(dòng)態(tài)內(nèi)存控制器DMC-40技術(shù)參考手冊(cè)

    DMC是由ARM開發(fā)、測(cè)試和許可的高級(jí)微控制器總線架構(gòu)(AMBA)。 DMC是一種高性能、區(qū)域優(yōu)化的SDRAM或移動(dòng)SDR存儲(chǔ)器控制器,與AMBA AXI協(xié)議兼容。 您可以使用多個(gè)選項(xiàng)配置DMC
    發(fā)表于 08-02 11:26

    SDR SDRAM Controller

    SDR SDRAM Controller Synchronous DRAM (SDRAM) has become a mainstream memory of choice in embedded
    發(fā)表于 05-14 11:04 ?46次下載

    ref sdr sdram verilog代碼

    ref-sdr-sdram-verilog代碼 SDR SDRAM Controller v1.1 readme.txt This readme file for the SDR
    發(fā)表于 06-14 08:50 ?33次下載

    SDR SDRAM Controller (White Pa

    SDR SDRAM Controller August 2002, ver. 1.1 1M-WP-SDR-1.1 IntroductionThe single data rate (SDR
    發(fā)表于 06-14 08:51 ?95次下載

    ref sdr sdram vhdl代碼

    ref-sdr-sdram-vhdl代碼 SDR SDRAM Controller v1.1 readme.txt This readme file for the SDR
    發(fā)表于 06-14 08:52 ?46次下載

    標(biāo)準(zhǔn)SDR SDRAM控制器參考設(shè)計(jì),Lattice提供Vr

    標(biāo)準(zhǔn)SDR SDRAM控制器參考設(shè)計(jì) Lattice提供Vrilog代碼 // Permission:////   Lattice Semiconductor grants
    發(fā)表于 06-14 09:23 ?76次下載

    SDRAM的引腳封裝標(biāo)準(zhǔn)

    SDRAM從發(fā)展到現(xiàn)在已經(jīng)經(jīng)歷了五代,分別是:第一代SDR SDRAM,第二代DDR SDRAM,第三代DDR2 SDRAM,第四代DDR3
    發(fā)表于 04-03 16:04 ?1845次閱讀

    基于SDR SDRAM ControllerSRAM存儲(chǔ)器的參考設(shè)計(jì)

    View the reference design for SDR SDRAM Controller. http://www.xsypw.cn/soft/ has thousands of reference designs to help bring your
    發(fā)表于 06-27 08:08 ?9次下載
    基于<b class='flag-5'>SDR</b> <b class='flag-5'>SDRAM</b> ControllerSRAM存儲(chǔ)器的參考設(shè)計(jì)
    主站蜘蛛池模板: 精品免费视在线视频观看| 久操免费在线| 午夜影院免费观看| 天天干天天曰| 久久国产成人午夜aⅴ影院| 亚洲视频一区网站| 情趣店上班h系列小说| 这里只有精品在线| 在线观看视频一区二区三区| 日本亚洲卡一卡2卡二卡三卡四卡| 中文字幕欧美日韩| 特级毛片免费视频播放| 欧美大片一区| bt天堂中文在线| 久久久久88色偷偷免费| 美女扒开尿口给男人桶爽视频| 一区二区三区四区在线观看视频| 天天看片天天操| 久青草国产在线视频_久青草免| www射射一区| 欧美3区| 在线精品一区二区三区| 久久国产精品99久久久久久老狼 | 免费大片黄在线观看| 欧美大胆一级视频| 久久天天躁狠狠躁夜夜爽 | 婷婷国产| 色综合网址| 国产精品美女视频| 久久人人视频| 亚洲国产精品嫩草影院| 久久久久久9| 日日做夜夜爽夜夜爽| 亚洲欧美在线观看| 伦理片第一页| 色四虎| 亚洲国产成人久久一区久久| www.91免费视频| 日本一区二区视频| 国产免费色视频| 国产午夜视频在线观看第四页 |