Sdram手册分析以及部分代码编写总结

一. SDRAM基础特性

在这里插入图片描述

1.内部存储(Memory)

  • bank-row-column
  • 一共有4个bank,每个bank有213行,每一行有29列,每一个为16bit

2.刷新周期

8192refresh cycles/64ms,平均每 7.8us 刷新一行

3.数据读写和命令发送介绍

  • SDRAM提供可编程突发长度的可编程读或写突发长度:1、2、4、8个位置或整页。(一页表示一行)
  • 数据读写和命令发送都同步于sdram时钟上升沿
  • 数据断电丢失
  • 半双工并行通信,一次传输16bit

4.预充电和刷新的区别

  • precharge all bank :一次刷新所有行(不定期)
  • auto refresh:一次刷新某一行(定期)

二. 引脚描述

请添加图片描述
行地址13个,列地址9个,所以每个Bank=2^13 行*2^9 ,一页突发表示一行的突发


  • CLK:SDRAM工作的时钟,这款芯片最高支持133M,所以要设定为133M以下
  • CKE:时钟使能信号
  • CS#:SDRAM片选信号(#表示低电平有效)
  • CAS#,RAS#,WE#:这三个信号构成了对SDRAM的命令信号
  • DQM:数据输入/输出掩码
  • BA[1:0]:Bank地址,
  • A[12:0]:地址线,当我们选择SDRAM某个Bank的Row(行)址的时候,需要到13根地址线(A0~A12);当选择Col(列)的时候,只用A0~A8这9根线;A10这个信号可以用来控制Auto-precharge
    DQ [15:0]:双向数据总线(三态门)

三. AC特性表(需要的延时)

请添加图片描述

CAS:Column Address Select列选地址

RAS:Row Address Select 行选地址

latency:延迟


一些在代码中需要的延时时间

在这里插入图片描述

四. 模式寄存器设置

在这里插入图片描述

write model,burst type,CAS latency,Burst Length

  • OP_MODE (写模式控制):突发写读/突发写单个读
  • CAS_LATENCY (列选址延时):2/3(单位:clk)
  • BURST_TYPE (突发类型 ):1时不能全页读写
  • BURST_LENTH (突发长度 ):1/2/4/8/512 (每个数据:16bit)

五. 命令真值表,掩码

在这里插入图片描述
在这里插入图片描述

H: 高电平, L: 低电平, X: 不关心

在代码中需要用到的命令

  • PRE_ALL_BANK (预充电所有bank)
  • AUTO_REFRSH (自动刷新)
  • MODE_REGISTER_SET(模式寄存器设置)
  • ROW_ACTIVE(行激活)
  • READ
  • WRITE
  • BURST_STOP(读写都可以终止)
  • NO_OPREATION(无操作):该命令不会影响前一个命令执行的操作,该命令主要是为了保护当前的操作不会受到影响

六. 需要用到的时序图

1.写入NO_OPERATION,ROW_ACTIVE命令的时序图

在这里插入图片描述

2.读数据的时序图

在这里插入图片描述

在这里插入图片描述

  • 读操作命令后根据设置的cas_latency(2/3clk)决定采样数据时间
  • 发送完写(READ)命令后,下一个上升沿以后发送无操作(NOP)命令
  • 在每一个时钟上升沿读取数据

3.写数据的时序图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-plyoYcts-1645344996014)(C:\Users\DELL\Desktop\Revision\Protocol_Verilog\sdram_uart\doc\部分图\image-20220220154714238.png)]

  • 发送完写(WRITE)命令后,下一个上升沿以后发送无操作(NOP)命令
  • 在每一个时钟上升沿写入数据

4.写到预充电的时序图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UiWN5xAb-1645344996014)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20220220155103890.png)]

写完数据后有一个T_DPL的延时

七. 代码、状态图、整体框架

1.整体框架

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ycLMeBUg-1645344996015)(C:\Users\DELL\Desktop\Revision\Protocol_Verilog\sdram_uart\doc\部分图\image-20220220155717486.png)]

2.状态转换图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qZOrrvav-1645344996015)(C:\Users\DELL\Desktop\Revision\Protocol_Verilog\sdram_uart\doc\部分图\image-20220220155539256.png)]

3 .代码

(1) sdram_interface(sdram接口代码)

module sdram_interface (
    input              clk          ,//100sdram时钟
    input              rst_n        ,
    input     [15:0]   write_data   ,//写入的数据
    input     [1:0]    req          ,//读写请求
    input     [14:0]   mode_set     ,//模式选择:bank+A0-A10
    input     [23:0]   addr         ,//bank+行地址+列地址(2+13+9) 
    output    [15:0]   read_data    ,//读取的数据
    output             write_data_vld,
    output             read_data_vld,

    output             cke          ,//时钟使能
    output             cs_n         ,//片选,低电平有效
    output    [1:0]    bank         ,//块地址    
    output    [12:0]   rc_addr      ,//行列地址设置 
    output             ras_n        ,//行选址,低电平有效
    output             cas_n        ,//列选址,低电平有效
    output             we_n         ,//低电平有效
    output    [1:0]    dqm          ,//掩码
    inout     [15:0]   dq           //数据输入输出


);
/* 参数定义 */
//状态参数
localparam      POWER_ON    = 10'b00000_00001,
                PRE_ALL1    = 10'b00000_00010,
                AUTO_REF1   = 10'b00000_00100,
                MODE_SET    = 10'b00000_01000,
                IDLE        = 10'b00000_10000,
                AUTO_REF2   = 10'b00001_00000,
                ROW_ACTIVE  = 10'b00010_00000,
                READ        = 10'b00100_00000,
                WRITE       = 10'b01000_00000,
                PRE_ALL2    = 10'b10000_00000;

//延时参数
localparam     T_START = 20000 ,// 上电后等待200us
               TRP     = 2     ,// 行预充电30ns           
               TRRC    = 8     ,// 自刷新80ns           
               TMRD    = 2     ,// 模式设置后与新命令之间的间隔时间           
               TRCD    = 2     ,// 行激活与列激活间隔时间
               T_FRESH = 700   ,// 一行数据读写完的刷新时间          
               TDPL    = 2     ;// 写完后与预充电命令的间隔时间  

//命令参数
localparam     PRE_ALL_CMD     = 4'b0010,        
               AUTO_REF_CMD    = 4'b0001,
               MODE_SET_CMD    = 4'b0000,         
               ROW_ACTIVE_CMD  = 4'b0011,             
               READ_CMD        = 4'b0101,     
               WRITE_CMD       = 4'b0100,
               BURST_STOP_CMD  = 4'b0110,          
               NOP_CMD         = 4'b0111;     

//突发参数
localparam    BURST_LENTH_1     = 1  ,
              BURST_LENTH_2     = 2  ,
              BURST_LENTH_4     = 4  ,
              BURST_LENTH_8     = 8  ,
              BURST_LENTH_FULL  = 512;//全页突发模式,自定义读写字节数(<=512)
/* 信号定义 */
wire [15:0]     dq_in;
wire [15:0]     dq_out;
wire            dq_out_enable;

reg  [3:0]  command   ; //cs_n+cas_n+ras_n+we_n
reg         cke_r     ;
reg  [1:0]  bank_r    ;
reg  [12:0] rc_addr_r ;  
reg  [1:0]  dqm_r     ; 
reg         read_req  ;
reg         write_req ;

reg  [11:0]  burst_num;//突发长度



//计数器
reg  [9:0]  fresh_cnt;     //行刷新计数器
wire        add_fresh_cnt;
wire        end_fresh_cnt;
reg         fresh_flag;   //刷新标志
reg         fresh_cnt_flag;//刷新计时开始标志

reg  [14:0] delay_cnt;    //延时计数器
wire        add_delay_cnt;
wire        end_delay_cnt;
reg  [14:0] delay_cnt_sel;//延时选择
reg         delay_cnt_falg;//延时开始标志

reg  [11:0]  byte_cnt;     //字节计数器
wire        add_byte_cnt;
wire        end_byte_cnt;
reg         read_end_flag;//读写结束到需要延时的标志
reg         write_end_flag;//读写结束到需要延时的标志


//状态跳转条件
wire        power_preall1 ;
wire        preall1_atref1;
wire        atref1_modeset;
wire        modeset_idle  ;
wire        idle_atref2   ;
wire        idle_rowact   ;
wire        atref2_idle   ;
wire        rowact_read   ;
wire        rowact_write  ;
wire        read_preall2  ;
wire        write_preall2 ;
wire        preall2_idle  ;

reg [9:0] state_c;
reg [9:0] state_n;


/* 代码编写 */
//状态转换
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        state_c <= POWER_ON;
    end 
    else begin 
        state_c <= state_n;
    end 
end

//转换规律
always @(*) begin
    case(state_c)
        POWER_ON : 
                if (power_preall1) begin
                    state_n = PRE_ALL1;            
                end 
                else begin
                    state_n = state_c;
                end
        PRE_ALL1 : 
                if (preall1_atref1) begin
                    state_n = AUTO_REF1;            
                end 
                else begin
                    state_n = state_c;
                end
        AUTO_REF1 : 
                if (atref1_modeset) begin
                    state_n = MODE_SET;            
                end 
                else begin
                    state_n = state_c;
                end
        MODE_SET : 
                if (modeset_idle) begin
                    state_n = IDLE;            
                end 
                else begin
                    state_n = state_c;
                end
        IDLE : 
                if (idle_atref2) begin
                    state_n = AUTO_REF2;            
                end 
                else if (idle_rowact) begin
                    state_n = ROW_ACTIVE;
                end
                else begin
                    state_n = state_c;
                end
        AUTO_REF2 : 
                if (atref2_idle) begin
                    state_n = IDLE;            
                end 
                else begin
                    state_n = state_c;
                end
        ROW_ACTIVE : 
                if (rowact_read) begin
                    state_n = READ;            
                end 
                else if (rowact_write) begin
                    state_n = WRITE;            
                end 
                else begin
                    state_n = state_c;
                end
        READ : 
                if (read_preall2) begin
                    state_n = PRE_ALL2;            
                end 
                else begin
                    state_n = state_c;
                end
        WRITE : 
                if (write_preall2) begin
                    state_n = PRE_ALL2;            
                end 
                else begin
                    state_n = state_c;
                end
        PRE_ALL2 : 
                if (preall2_idle) begin
                    state_n = IDLE;            
                end 
                else begin
                    state_n = state_c;
                end
        default : state_n <= state_c ;
    endcase
end


//转换条件
assign power_preall1     = state_c ==  POWER_ON   && end_delay_cnt;                      
assign preall1_atref1    = state_c ==  PRE_ALL1   && end_delay_cnt;               
assign atref1_modeset    = state_c ==  AUTO_REF1  && end_delay_cnt;                     
assign modeset_idle      = state_c ==  MODE_SET   && end_delay_cnt;                      
assign idle_atref2       = state_c ==  IDLE       && fresh_flag;              
assign idle_rowact       = state_c ==  IDLE       && (read_req || write_req);                     
assign atref2_idle       = state_c ==  AUTO_REF2  && end_delay_cnt;                        
assign rowact_read       = state_c ==  ROW_ACTIVE && end_delay_cnt && read_req;                      
assign rowact_write      = state_c ==  ROW_ACTIVE && end_delay_cnt && write_req;                       
assign read_preall2      = state_c ==  READ       && end_delay_cnt;                         
assign write_preall2     = state_c ==  WRITE      && end_delay_cnt;                        
assign preall2_idle      = state_c ==  PRE_ALL2   && end_delay_cnt;                      


//fresh计数器
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        fresh_cnt <= 0;
    end 
    else if (atref2_idle) begin
        fresh_cnt <= 0;//行刷新完计数回归0
    end
    else if(add_fresh_cnt)begin 
            if(end_fresh_cnt)begin 
                fresh_cnt <= 0;
            end
            else begin 
                fresh_cnt <= fresh_cnt + 1;
            end 
    end
   else  begin
       fresh_cnt <= fresh_cnt;
    end
end 

assign add_fresh_cnt = fresh_cnt_flag;
assign end_fresh_cnt = add_fresh_cnt && fresh_cnt == T_FRESH - 1;


//fresh_flag
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        fresh_flag <= 0;
    end 
    else if(end_fresh_cnt)begin 
       fresh_flag <= 1'b1; 
    end 
    else if (idle_atref2) begin
       fresh_flag <= 1'b0; 
    end
end

//fresh_cnt_flag
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        fresh_cnt_flag <= 0;
    end 
    else if(modeset_idle)begin 
        fresh_cnt_flag <= 1'b1;
    end 
end

//delay计数器
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        delay_cnt <= 0;
    end 
    else if(add_delay_cnt)begin 
            if(end_delay_cnt)begin 
                delay_cnt <= 0;
            end
            else begin 
                delay_cnt <= delay_cnt + 1;
            end 
    end
   else  begin
       delay_cnt <= delay_cnt;
    end
end 

assign add_delay_cnt = delay_cnt_falg;
assign end_delay_cnt = add_delay_cnt && delay_cnt ==delay_cnt_sel - 1 ;

//delay_cnt_sel延时时间选择
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        delay_cnt_sel <= 0;
    end 
    else if(state_c == POWER_ON )begin 
       delay_cnt_sel <= T_START; 
    end 
    else begin
        case(state_c) 
            PRE_ALL1   :    delay_cnt_sel <= TRP  ;        
            AUTO_REF1  :    delay_cnt_sel <= TRRC ;     
            MODE_SET   :    delay_cnt_sel <= TMRD ;     
            AUTO_REF2  :    delay_cnt_sel <= TRRC ;     
            ROW_ACTIVE :    delay_cnt_sel <= TRCD ;     
            READ       :    delay_cnt_sel <= TRP  ;    
            WRITE      :    delay_cnt_sel <= TDPL ;     
            PRE_ALL2   :    delay_cnt_sel <= TRP  ;    
            default    :    delay_cnt_sel <= TRP  ; 
        endcase        
    end 
end

//delay_cnt_falg延时开始标志
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        delay_cnt_falg <= 0;
    end 
    else if(state_n == POWER_ON || state_n == PRE_ALL1 || state_n ==AUTO_REF1 || state_n == MODE_SET)begin 
        delay_cnt_falg <= 1'b1;
    end 
    else if (state_n == ROW_ACTIVE) begin
         delay_cnt_falg <= 1'b1;
    end
    else if(state_n == PRE_ALL2 )begin 
        delay_cnt_falg <= 1'b1;
    end 
    else if (state_n == READ && read_end_flag) begin
        delay_cnt_falg <= 1'b1;
    end
    else if (state_n == WRITE && write_end_flag) begin
        delay_cnt_falg <= 1'b1;
    end
    else if (state_n ==AUTO_REF2 ) begin
        delay_cnt_falg <= 1'b1;
    end
    else begin
        delay_cnt_falg <= 1'b0;
    end
end

//cas_latency,byte_cnt,字节数=读写字节数+cas_lastency
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        byte_cnt <= 0;
    end 
    else if (preall2_idle) begin
        byte_cnt <= 0;
    end
    else if(add_byte_cnt)begin 
            if(end_byte_cnt)begin 
                byte_cnt <= 0;
            end
            else begin 
                byte_cnt <= byte_cnt + 1;
            end 
    end
   else  begin
       byte_cnt <= byte_cnt;
    end
end 

assign add_byte_cnt = state_c == READ || state_c == WRITE;
assign end_byte_cnt = add_byte_cnt && byte_cnt == 525;

//read_end_flag.write_end_flag
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        read_end_flag <= 0;
        write_end_flag <= 0;
    end 
    else if(state_c == READ && byte_cnt == burst_num - 1+2 )begin 
        read_end_flag <= 1'b1;
    end 
    else if(state_c == WRITE && byte_cnt == burst_num - 1)begin 
        write_end_flag <= 1'b1;
    end
    else if (write_preall2) begin
        write_end_flag <= 1'b0;
    end 
    else if(read_preall2 )begin 
        read_end_flag <= 1'b0;
    end 
end

//burst_num
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        burst_num <= 1;
    end 
    else begin
        case (mode_set[2:0])
            3'b000  : burst_num = BURST_LENTH_1   ; 
            3'b001  : burst_num = BURST_LENTH_2   ;
            3'b010  : burst_num = BURST_LENTH_4   ;
            3'b011  : burst_num = BURST_LENTH_8   ;
            3'b111  : burst_num = BURST_LENTH_FULL;
            default : burst_num = 1;
        endcase   
    end

end
//command
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        command <= NOP_CMD;
    end 
    else if (atref1_modeset) begin
       command <= MODE_SET_CMD; 
    end
    else if(power_preall1 || read_preall2 || write_preall2)begin 
        command <= PRE_ALL_CMD;
    end 
    else if((state_c == WRITE && byte_cnt == burst_num - 1))begin 
        command <= BURST_STOP_CMD;
    end 
    else if(idle_atref2 ||preall1_atref1)begin 
        command <= AUTO_REF_CMD;
    end 
    else if (idle_rowact) begin
        command <= ROW_ACTIVE_CMD;
    end
    else if (rowact_read ) begin
        command <= READ_CMD;
    end
    else if (rowact_write ) begin
        command <= WRITE_CMD;
    end
    else begin
        command <= NOP_CMD;
    end
end

//read_data,从sdram读取的数据
assign  read_data = (state_c == READ  && byte_cnt >= 2 && byte_cnt <= burst_num - 1 +2)?dq_in:1'b0;
assign  read_data_vld = (state_c == READ  && byte_cnt >= 2 && byte_cnt <= burst_num - 1+2 )?1'b1:1'b0;
assign  write_data_vld = (state_c == WRITE && byte_cnt <= burst_num - 1)?1'b1:1'b0;
assign  dq_out         = (state_c == WRITE && byte_cnt <= burst_num - 1)?write_data:1'b0;
assign  dq_out_enable  = (state_c == WRITE && byte_cnt <= burst_num - 1)?1'b1:1'b0;

//read_req,write_req
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        read_req <= 0;
        write_req <= 0;
    end 
    else if(req[1])begin 
        read_req<=1'b1;
    end 
    else if(req[0])begin 
        write_req<=1'b1;
    end 
    else if (read_preall2 || write_preall2)begin 
        read_req <= 0;
        write_req <= 0;
    end 
end

//bank_r,rc_addr_r
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        bank_r <= 0;
        rc_addr_r <=0;
    end 
    else if (atref1_modeset) begin
        bank_r <= mode_set[14:13];
        rc_addr_r <= mode_set[12:0]; 
    end
    else if(idle_rowact)begin 
        bank_r <= addr[23:22];
        rc_addr_r <= addr[21:9];
    end 
    else if (rowact_read || rowact_write) begin
        rc_addr_r <= {4'b0,addr[8:0]};
    end
end

//dq
assign dq_in = dq;
assign dq = dq_out_enable?dq_out:1'bz;

//与sdram的接口
assign cke     = 1'b1;
assign cs_n    = command[3] ;
assign bank    = bank_r     ;
assign rc_addr = rc_addr_r  ; 
assign ras_n   = command[2] ;
assign cas_n   = command[1] ;
assign we_n    = command[0] ;
assign dqm     = 2'b00;//不需要隐藏数据

endmodule //sdram_interface

(2). sdram_ctrl(sdram控制模块代码)

module sdram_ctrl (
    input              clk         ,
    input              rst_n       ,
    input  [1:0]       key_down    ,//按键

    output     [15:0]  write_data  ,//输出:接口模块的信号
    output reg [1:0]   req         ,
    output reg [14:0]  mode_set    ,
    output reg [23:0]  addr        ,
    output             clk_100m    ,

    input   [15:0]     read_data   ,//输入:接口模块的信号
    input              write_data_vld,
    input              read_data_vld,

//UART_TX信号
    input              busy        , 
    output    [7:0]    tx_data     ,//传入uart_tx的数据
    output             tx_data_vld ,
//UART_RX信号
    input   [7:0]      rx_data     ,//输入的数据
    input              rx_data_vld 

);


/* 参数定义 */
//MODE_SET模式设置参数   
localparam    OP_MODE     =  1'b0  ,//写模式控制
              CAS_LATENCY =  3'b010,//列选址延时
              BURST_TYPE  =  1'b0  ,//突发类型
              BURST_LENTH =  3'b111;//突发长度

//读写地址
localparam    RW_ADDR     = 16'h0;


pll_100m	pll_100m_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk),
	.c0 ( clk_100m )
);

//req
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        req <= 2'b0;
    end 
    else if(key_down[1])begin 
        req[1] =1'b1;
    end 
    else if(key_down[0])begin 
        req[0] =1'b1;
    end 
    else begin 
        req <= 2'b0;
    end 
end


//mode_set
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        mode_set <= 0;
    end 
    else begin 
        mode_set <= {5'b0,OP_MODE,2'b0,CAS_LATENCY,BURST_TYPE,BURST_LENTH};
    end 
end

//addr
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        addr <= 16'h0;
    end 
    else begin 
        addr <= RW_ADDR;
    end 
end




/* fifo */
//write_fifo 从UART_RX接受到数据写入sdram
write_fifo	write_fifo_inst (
	.aclr                   ( ~rst_n        ),
	.data                   ( wfifo_data_in ),
	.rdclk                  ( clk_100m      ),
	.rdreq                  ( wfifo_rdreq   ),
	.wrclk                  ( clk           ),
	.wrreq                  ( wfifo_wrreq   ),
	.q                      ( wfifo_data_out),
	.rdempty                ( wfifo_rdempty ),
	.rdfull                 ( wfifo_rdfull  ),
	.rdusedw                ( wfifo_rdusedw ),
	.wrempty                ( wfifo_wrempty ),
	.wrfull                 ( wfifo_wrfull  ),
	.wrusedw                ( wfifo_wrusedw )
	);   
//wfifo读的信号         
wire        wfifo_rdreq     ;          
wire [15:0] wfifo_data_out  ;          
wire        wfifo_rdempty   ;   
wire        wfifo_rdfull    ;   
wire [11:0]  wfifo_rdusedw   ;
//wfifo写的信号
wire [15:0] wfifo_data_in   ;  
wire        wfifo_wrreq     ;     
wire        wfifo_wrempty   ;   
wire        wfifo_wrfull    ;   
wire [11:0]  wfifo_wrusedw   ;   

//写入wfifo
assign      wfifo_wrreq = rx_data_vld && ~wfifo_wrfull;
assign      wfifo_data_in = rx_data;     

//读取fifo数据给sdram
assign      wfifo_rdreq =  ~wfifo_rdempty && write_data_vld;
assign      write_data  = wfifo_data_out ;


//read_fifo 从sdram中读取数据传入给UART_TX
read_fifo	read_fifo_inst (
	.aclr                   ( ~rst_n        ),
	.data                   ( rfifo_data_in ),
	.rdclk                  ( clk           ),
	.rdreq                  ( rfifo_rdreq   ),
	.wrclk                  ( clk_100m      ),
	.wrreq                  ( rfifo_wrreq   ),
	.q                      ( rfifo_data_out),
	.rdempty                ( rfifo_rdempty ),
	.rdfull                 ( rfifo_rdfull  ),
	.rdusedw                ( rfifo_rdusedw ),
	.wrempty                ( rfifo_wrempty ),
	.wrfull                 ( rfifo_wrfull  ),
	.wrusedw                ( rfifo_wrusedw )
	);


//rfifo读的信号         
wire        rfifo_rdreq     ;          
wire [15:0] rfifo_data_out  ;          
wire        rfifo_rdempty   ;   
wire        rfifo_rdfull    ;   
wire [11:0]  rfifo_rdusedw   ;
//rfifo写的信号
wire [15:0] rfifo_data_in   ;  
wire        rfifo_wrreq     ;     
wire        rfifo_wrempty   ;   
wire        rfifo_wrfull    ;   
wire [11:0]  rfifo_wrusedw   ;   


//写入fifo
assign   rfifo_wrreq = read_data_vld && ~wfifo_wrfull ;
assign   rfifo_data_in =read_data;

//读取rfifo数据给uart_tx
assign rfifo_rdreq =  ~busy && ~rfifo_rdempty;
assign tx_data_vld = rfifo_rdreq;
assign tx_data     = rfifo_data_out; 
endmodule //sdram_ctrl

(3). TOP(顶层代码)

module top (
    input              clk      ,
    input              rst_n    ,
       
    input     [1:0]    key_in   ,
//串口接口
    input              uart_rxd ,
    output             uart_txd ,
//sdram接口
    output             clk_100m ,
    output             cke      ,
    output             cs_n     ,
    output    [1:0]    bank     ,
    output    [12:0]   rc_addr  ,
    output             ras_n    ,
    output             cas_n    ,
    output             we_n     ,
    output    [1:0]    dqm      ,
    inout     [15:0]   dq          

);
//sdram_ctrl与sdram_interface连接的信号
wire [15:0]     write_data;//写入sdram的数据
wire [1:0]      req       ;//读写请求
wire [14:0]     mode_set  ;//sdram模式设置
wire [23:0]     addr      ;//bank+行+列地址


//sdram_interface与sdram_ctrl连接的信号
wire [15:0]     read_data ;//从sdram读取的数据
wire [1:0]      key_down  ;//按键检测
(* keep *) wire            write_data_vld;
(* keep *) wire            read_data_vld ;

//串口与sdram连接的信号
wire                 busy       ;//串口正在传数据
wire      [7:0]      rx_data    ;//串口接受到的数据  
wire                 rx_data_vld;//接收数据有效
wire      [7:0]      tx_data    ;//串口传输数据
wire                 tx_data_vld;//串口传输数据有效

uart_rx u_uart_rx(
    /* input           */     .clk        (clk        ) ,
    /* input           */     .rst_n      (rst_n      ) ,
    /* input           */     .uart_rxd   (uart_rxd   ) ,
    /*     */
    /* output   [7:0]  */     .rx_data    (rx_data    ) ,
    /* output          */     .rx_data_vld(rx_data_vld) 

);

uart_tx u_uart_tx(
    /* input          */      .clk        (clk        ) ,
    /* input          */      .rst_n      (rst_n      ) ,
    /* input    [7:0] */      .tx_data    (tx_data    ) ,
    /* input          */      .tx_data_vld(tx_data_vld) ,

    /* output         */      .busy       (busy       ) ,
                              .uart_txd   (uart_txd   )

);

//sdram_ctrl
sdram_ctrl u_sdram_ctrl(
    /* input             */  .clk       (clk       )            ,
    /* input             */  .rst_n     (rst_n     )            ,
    /* input  [1:0]      */  .key_down  (key_down  )            ,//按键

    /* output reg [15:0] */  .write_data(write_data)            ,//输出:接口模块的信号
    /* output reg [1:0]  */  .req       (req       )            ,
    /* output reg [14:0] */  .mode_set  (mode_set )             ,
    /* output reg [23:0] */  .addr      (addr      )            ,
    /* output            */  .clk_100m  (clk_100m  )            ,

    /* input   [15:0]    */  .read_data (read_data )            ,//输入:接口模块的信号
                            .write_data_vld(write_data_vld)     ,
                            .read_data_vld(read_data_vld)       ,
    /*  */
    /*  */
    /* //UART_TX信号 */
    /*     input         */ .busy       (busy       ) , 
    /*     output  [7:0] */ .tx_data    (tx_data    ) ,//传入uart_tx的数据
    /*     output        */ .tx_data_vld(tx_data_vld) ,
    /* //UART_RX信号 */
    /*     input   [7:0] */ .rx_data    (rx_data    ) ,//输入的数据
    /*     input         */ .rx_data_vld(rx_data_vld) 

    
);


//sdram_interface
sdram_interface u_sdram_interface(
    /* input             */  .clk       (clk_100m  )        ,//100sdram时钟
    /* input             */  .rst_n     (rst_n     )        ,
    /* input     [15:0]  */  .write_data(write_data)        ,//写入的数据
    /* input     [1:0]   */  .req       (req       )        ,//读写请求
    /* input     [14:0]  */  .mode_set (mode_set )          ,//模式选择:bank+A0-A10
    /* input     [23:0]  */  .addr      (addr      )        ,//bank+行地址+列地址(2+13+9) 
    /* output    [15:0]  */  .read_data (read_data )        ,//读取的数据
                             .write_data_vld(write_data_vld),
                             .read_data_vld(read_data_vld)  ,

    /* output            */  .cke       (cke       )        ,//时钟使能
    /* output            */  .cs_n      (cs_n      )        ,//片选,低电平有效
    /* output    [1:0]   */  .bank      (bank      )        ,//块地址    
    /* output    [12:0]  */  .rc_addr   (rc_addr   )        ,//行列地址设置 
    /* output            */  .ras_n     (ras_n     )        ,//行选址,低电平有效
    /* output            */  .cas_n     (cas_n     )        ,//列选址,低电平有效
    /* output            */  .we_n      (we_n      )        ,//低电平有效
    /* output    [1:0]   */  .dqm       (dqm       )        ,//掩码
    /* inout     [15:0]  */  .dq        (dq        )        //数据输入输出


);


key_debounce u_key_debounce (
        /* 	input					 */.clk		(clk	),
        /* 	input					 */.rst_n	(rst_n	),
        /* 	input		[KEY_W-1:0] */ .key_in  (key_in ),
        /* 	 */ 
        /* 	output	reg	[KEY_W-1:0] */ .key_out (key_down)	 //检测到按下,输出一个周期的高脉冲,其他时刻为0
);
endmodule //top
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>