野火FPGA进阶(3):SDRAM读写控制器的设计与验证
创始人
2024-03-07 04:49:51
0

文章目录

    • 第50讲:SDRAM读写控制器的设计与验证
      • 理论部分
      • 设计与实现
      • 1. sdram_ctrl
        • sdram_init
        • sdram_a_ref
        • sdram_write
        • sdram_read
        • sdram_arbit
        • sdram_ctrl
      • 2. sdram_top
        • fifo_ctrl
        • sdram_top
      • 3. uart_sdram
        • uart_rx
        • uart_tx
        • fifo_read
        • uart_sdram

第50讲:SDRAM读写控制器的设计与验证

理论部分

SDRAM全称“Synchronous Dynamic Random Access Memory”,译为“同步动态随机存取内存”或“同步动态随机存储器”,是动态随机存储器(Dynamic Random Access Memory,DRAM)家族的一份子。

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


设计与实现

在这里插入图片描述

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

在这里插入图片描述

1. sdram_ctrl

sdram_init

`timescale  1ns/1nsmodule  sdram_init
(input   wire            sys_clk     ,   //系统时钟,频率100MHzinput   wire            sys_rst_n   ,   //复位信号,低电平有效output  reg     [3:0]   init_cmd    ,   //初始化阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}output  reg     [1:0]   init_ba     ,   //初始化阶段Bank地址output  reg     [12:0]  init_addr   ,   //初始化阶段地址数据,辅助预充电操作//和配置模式寄存器操作,A12-A0,共13位output  wire            init_end        //初始化结束信号
);// parameter    define
parameter   T_POWER     =   15'd20_000  ;   //上电后等待时钟数(200us)
//SDRAM初始化用到的控制信号命令
parameter   P_CHARGE    =   4'b0010     ,   //预充电指令AUTO_REF    =   4'b0001     ,   //自动刷新指令NOP         =   4'b0111     ,   //空操作指令M_REG_SET   =   4'b0000     ;   //模式寄存器设置指令
//SDRAM初始化过程各个状态
parameter   INIT_IDLE   =   3'b000      ,   //初始状态INIT_PRE    =   3'b001      ,   //预充电状态INIT_TRP    =   3'b011      ,   //预充电等待          tRPINIT_AR     =   3'b010      ,   //自动刷新INIT_TRF    =   3'b100      ,   //自动刷新等待        tRCINIT_MRS    =   3'b101      ,   //模式寄存器设置INIT_TMRD   =   3'b111      ,   //模式寄存器设置等待  tMRDINIT_END    =   3'b110      ;   //初始化完成
parameter   TRP_CLK     =   3'd2        ,   //预充电等待周期,20nsTRC_CLK     =   3'd7        ,   //自动刷新等待,70nsTMRD_CLK    =   3'd3        ;   //模式寄存器设置等待周期,30ns// wire define
wire            wait_end        ;   //上电后200us等待结束标志
wire            trp_end         ;   //预充电等待结束标志
wire            trc_end         ;   //自动刷新等待结束标志
wire            tmrd_end        ;   //模式寄存器设置等待结束标志// reg  define
reg     [14:0]  cnt_200us       ;   //SDRAM上电后200us稳定期计数器
reg     [2:0]   init_state      ;   //SDRAM初始化状态
reg     [2:0]   cnt_clk         ;   //时钟周期计数,记录初始化各状态等待周期数
reg             cnt_clk_rst     ;   //时钟周期计数复位标志
reg     [3:0]   cnt_init_aref   ;   //初始化过程自动刷新次数计数器//cnt_200us:SDRAM上电后200us稳定期计数器
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_200us   <=  15'd0;else    if(cnt_200us == T_POWER)cnt_200us   <=  T_POWER;elsecnt_200us   <=  cnt_200us + 1'b1;//wait_end:上电后200us等待结束标志
assign  wait_end = (cnt_200us == (T_POWER - 1'b1)) ? 1'b1 : 1'b0;//init_end:SDRAM初始化完毕信号
assign  init_end = (init_state == INIT_END) ? 1'b1 : 1'b0;//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_clk <=  3'd0;else    if(cnt_clk_rst == 1'b1)cnt_clk <=  3'd0;elsecnt_clk <=  cnt_clk + 1'b1;//cnt_init_aref:初始化过程自动刷新次数计数器
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_init_aref   <=  4'd0;else    if(init_state == INIT_IDLE)cnt_init_aref   <=  4'd0;else    if(init_state == INIT_AR)cnt_init_aref   <=  cnt_init_aref + 1'b1;elsecnt_init_aref   <=  cnt_init_aref;//trp_end,trc_end,tmrd_end:等待结束标志
assign  trp_end     =   ((init_state == INIT_TRP ) && (cnt_clk == TRP_CLK )) ? 1'b1 : 1'b0;
assign  trc_end     =   ((init_state == INIT_TRF ) && (cnt_clk == TRC_CLK )) ? 1'b1 : 1'b0;
assign  tmrd_end    =   ((init_state == INIT_TMRD) && (cnt_clk == TMRD_CLK)) ? 1'b1 : 1'b0;//SDRAM的初始化状态机
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)init_state  <=  INIT_IDLE;elsecase(init_state)INIT_IDLE:  //系统上电后,在初始状态等待200us跳转到预充电状态if(wait_end == 1'b1)init_state  <=  INIT_PRE;elseinit_state  <=  init_state;INIT_PRE:   //预充电状态,直接跳转到预充电等待状态init_state  <=  INIT_TRP;INIT_TRP:   //预充电等待状态,等待结束,跳转到自动刷新状态if(trp_end == 1'b1)init_state  <=  INIT_AR;elseinit_state  <=  init_state;INIT_AR :   //自动刷新状态,直接跳转到自动刷新等待状态init_state  <=  INIT_TRF;INIT_TRF:   //自动刷新等待状态,等待结束,自动跳转到模式寄存器设置状态if(trc_end == 1'b1)if(cnt_init_aref == 4'd8)init_state  <=  INIT_MRS;elseinit_state  <=  INIT_AR;elseinit_state  <=  init_state;INIT_MRS:   //模式寄存器设置状态,直接跳转到模式寄存器设置等待状态init_state  <=  INIT_TMRD;INIT_TMRD:  //模式寄存器设置等待状态,等待结束,跳到初始化完成状态if(tmrd_end == 1'b1)init_state  <=  INIT_END;elseinit_state  <=  init_state;INIT_END:   //初始化完成状态,保持此状态init_state  <=  INIT_END;default:    init_state  <=  INIT_IDLE;endcase//cnt_clk_rst:时钟周期计数复位标志
always@(*)begincase (init_state)INIT_IDLE:  cnt_clk_rst <=  1'b1;   //时钟周期计数复位信号,高有效,时钟周期计数清零INIT_TRP:   cnt_clk_rst <= (trp_end == 1'b1) ? 1'b1 : 1'b0;//等待结束标志有效,计数器清零INIT_TRF:   cnt_clk_rst <=  (trc_end == 1'b1) ? 1'b1 : 1'b0; //等待结束标志有效,计数器清零INIT_TMRD:  cnt_clk_rst <=  (tmrd_end == 1'b1) ? 1'b1 : 1'b0;//等待结束标志有效,计数器清零INIT_END:   cnt_clk_rst <=  1'b1;   //初始化完成,计数器清零default:    cnt_clk_rst <=  1'b0;endcaseend//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)begininit_cmd    <=  NOP;init_ba     <=  2'b11;init_addr   <=  13'h1fff;endelsecase(init_state)INIT_IDLE,INIT_TRP,INIT_TRF,INIT_TMRD:  //执行空操作指令begininit_cmd    <=  NOP;init_ba     <=  2'b11;init_addr   <=  13'h1fff;endINIT_PRE:   //预充电指令begininit_cmd    <=  P_CHARGE;init_ba     <=  2'b11;init_addr   <=  13'h1fff;end INIT_AR:    //自动刷新指令begininit_cmd    <=  AUTO_REF;init_ba     <=  2'b11;init_addr   <=  13'h1fff;endINIT_MRS:   //模式寄存器设置指令begininit_cmd    <=  M_REG_SET;init_ba     <=  2'b00;init_addr   <={    //地址辅助配置模式寄存器,参数不同,配置的模式不同3'b000,     //A12-A10:预留1'b0,       //A9=0:读写方式,0:突发读&突发写,1:突发读&单写2'b00,      //{A8,A7}=00:标准模式,默认3'b011,     //{A6,A5,A4}=011:CAS潜伏期,010:2,011:3,其他:保留1'b0,       //A3=0:突发传输方式,0:顺序,1:隔行3'b111      //{A2,A1,A0}=111:突发长度,000:单字节,001:2字节//010:4字节,011:8字节,111:整页,其他:保留};end INIT_END:   //SDRAM初始化完成begininit_cmd    <=  NOP;init_ba     <=  2'b11;init_addr   <=  13'h1fff;enddefault:begininit_cmd    <=  NOP;init_ba     <=  2'b11;init_addr   <=  13'h1fff;end    endcaseendmodule

sdram_a_ref

`timescale  1ns/1nsmodule  sdram_a_ref
(input   wire            sys_clk     ,   //系统时钟,频率100MHzinput   wire            sys_rst_n   ,   //复位信号,低电平有效input   wire            init_end    ,   //初始化结束信号input   wire            aref_en     ,   //自动刷新使能output  reg             aref_req    ,   //自动刷新请求output  reg     [3:0]   aref_cmd    ,   //自动刷新阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}output  reg     [1:0]   aref_ba     ,   //自动刷新阶段Bank地址output  reg     [12:0]  aref_addr   ,   //地址数据,辅助预充电操作,A12-A0,13位地址output  wire            aref_end        //自动刷新结束标志
);//parameter     define
parameter   CNT_REF_MAX =   10'd749     ;   //自动刷新等待时钟数(7.5us)
parameter   TRP_CLK     =   3'd2        ,   //预充电等待周期TRC_CLK     =   3'd7        ;   //自动刷新等待周期
parameter   P_CHARGE    =   4'b0010     ,   //预充电指令A_REF       =   4'b0001     ,   //自动刷新指令NOP         =   4'b0111     ;   //空操作指令
parameter   AREF_IDLE   =   3'b000      ,   //初始状态,等待自动刷新使能AREF_PCHA   =   3'b001      ,   //预充电状态AREF_TRP    =   3'b011      ,   //预充电等待          tRPAUTO_REF    =   3'b010      ,   //自动刷新状态AREF_TRF    =   3'b100      ,   //自动刷新等待        tRCAREF_END    =   3'b101      ;   //自动刷新结束//wire  define
wire            trp_end     ;   //预充电等待结束标志
wire            trc_end     ;   //自动刷新等待结束标志
wire            aref_ack    ;   //自动刷新应答信号//reg   define
reg     [9:0]   cnt_aref        ;   //自动刷新计数器
reg     [2:0]   aref_state      ;   //SDRAM自动刷新状态
reg     [2:0]   cnt_clk         ;   //时钟周期计数,记录自刷新阶段各状态等待时间
reg             cnt_clk_rst     ;   //时钟周期计数复位标志
reg     [1:0]   cnt_aref_aref   ;   //自动刷新次数计数器//cnt_ref:刷新计数器
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_aref    <=  10'd0;else    if(cnt_aref >= CNT_REF_MAX)cnt_aref    <=  10'd0;else    if(init_end == 1'b1)cnt_aref    <=  cnt_aref + 1'b1;else cnt_aref    <=  cnt_aref;//aref_req:自动刷新请求
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)aref_req    <=  1'b0;else    if(cnt_aref == CNT_REF_MAX - 1'b1)aref_req    <=  1'b1;else    if(aref_ack == 1'b1)aref_req    <=  1'b0;//aref_ack:自动刷新应答信号
assign  aref_ack = (aref_state == AREF_PCHA ) ? 1'b1 : 1'b0;
//aref_end:自动刷新结束标志
assign  aref_end = (aref_state == AREF_END  ) ? 1'b1 : 1'b0;//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_clk <=  3'd0;else    if(cnt_clk_rst == 1'b1)cnt_clk <=  3'd0;elsecnt_clk <=  cnt_clk + 1'b1;//trp_end,trc_end,tmrd_end:等待结束标志
assign  trp_end = ((aref_state == AREF_TRP) && (cnt_clk == TRP_CLK )) ? 1'b1 : 1'b0;
assign  trc_end = ((aref_state == AREF_TRF) && (cnt_clk == TRC_CLK )) ? 1'b1 : 1'b0;//cnt_aref_aref:初始化过程自动刷新次数计数器
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_aref_aref   <=  2'd0;else    if(aref_state == AREF_IDLE)cnt_aref_aref   <=  2'd0;else    if(aref_state == AUTO_REF)cnt_aref_aref   <=  cnt_aref_aref + 1'b1;elsecnt_aref_aref   <=  cnt_aref_aref;//SDRAM自动刷新状态机
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)aref_state  <=  AREF_IDLE;elsecase(aref_state)AREF_IDLE:if((aref_en == 1'b1) && (init_end == 1'b1))aref_state  <=  AREF_PCHA;elsearef_state  <=  aref_state;AREF_PCHA:aref_state  <=  AREF_TRP;AREF_TRP:if(trp_end == 1'b1)aref_state  <=  AUTO_REF;elsearef_state  <=  aref_state;AUTO_REF:aref_state  <=  AREF_TRF;AREF_TRF:if(trc_end == 1'b1)if(cnt_aref_aref == 2'd2)aref_state  <=  AREF_END;elsearef_state  <=  AUTO_REF;elsearef_state  <=  aref_state;AREF_END:aref_state  <=  AREF_IDLE;default:aref_state  <=  AREF_IDLE;endcase//cnt_clk_rst:时钟周期计数复位标志
always@(*)begincase (aref_state)AREF_IDLE:  cnt_clk_rst <=  1'b1;   //时钟周期计数器清零AREF_TRP:   cnt_clk_rst <=  (trp_end == 1'b1) ? 1'b1 : 1'b0;//等待结束标志有效,计数器清零AREF_TRF:   cnt_clk_rst <=  (trc_end == 1'b1) ? 1'b1 : 1'b0;//等待结束标志有效,计数器清零AREF_END:   cnt_clk_rst <=  1'b1;default:    cnt_clk_rst <=  1'b0;endcaseend//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginaref_cmd    <=  NOP;aref_ba     <=  2'b11;aref_addr   <=  13'h1fff;endelsecase(aref_state)AREF_IDLE,AREF_TRP,AREF_TRF:    //执行空操作指令beginaref_cmd    <=  NOP;aref_ba     <=  2'b11;aref_addr   <=  13'h1fff;endAREF_PCHA:  //预充电指令beginaref_cmd    <=  P_CHARGE;aref_ba     <=  2'b11;aref_addr   <=  13'h1fff;end AUTO_REF:   //自动刷新指令beginaref_cmd    <=  A_REF;aref_ba     <=  2'b11;aref_addr   <=  13'h1fff;endAREF_END:   //一次自动刷新完成beginaref_cmd    <=  NOP;aref_ba     <=  2'b11;aref_addr   <=  13'h1fff;end    default:beginaref_cmd    <=  NOP;aref_ba     <=  2'b11;aref_addr   <=  13'h1fff;end    endcaseendmodule

sdram_write

`timescale  1ns/1nsmodule  sdram_write
(input   wire            sys_clk         ,   //系统时钟,频率100MHzinput   wire            sys_rst_n       ,   //复位信号,低电平有效input   wire            init_end        ,   //初始化结束信号input   wire            wr_en           ,   //写使能input   wire    [23:0]  wr_addr         ,   //写SDRAM地址input   wire    [15:0]  wr_data         ,   //待写入SDRAM的数据(写FIFO传入)input   wire    [9:0]   wr_burst_len    ,   //写突发SDRAM字节数output  wire            wr_ack          ,   //写SDRAM响应信号output  wire            wr_end          ,   //一次突发写结束output  reg     [3:0]   write_cmd       ,   //写数据阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}output  reg     [1:0]   write_ba        ,   //写数据阶段Bank地址output  reg     [12:0]  write_addr      ,   //地址数据,辅助预充电操作,行、列地址,A12-A0,13位地址output  reg             wr_sdram_en     ,   //数据总线输出使能output  wire    [15:0]  wr_sdram_data       //写入SDRAM的数据
);//parameter     define
parameter   TRCD_CLK    =   10'd2   ,   //激活周期TRP_CLK     =   10'd2   ;   //预充电周期
parameter   WR_IDLE     =   4'b0000 ,   //初始状态WR_ACTIVE   =   4'b0001 ,   //激活WR_TRCD     =   4'b0011 ,   //激活等待WR_WRITE    =   4'b0010 ,   //写操作WR_DATA     =   4'b0100 ,   //写数据WR_PRE      =   4'b0101 ,   //预充电WR_TRP      =   4'b0111 ,   //预充电等待WR_END      =   4'b0110 ;   //一次突发写结束
parameter   NOP         =   4'b0111 ,   //空操作指令ACTIVE      =   4'b0011 ,   //激活指令WRITE       =   4'b0100 ,   //数据写指令B_STOP      =   4'b0110 ,   //突发停止指令P_CHARGE    =   4'b0010 ;   //预充电指令//wire  define
wire            trcd_end    ;   //激活等待周期结束
wire            twrite_end  ;   //突发写结束
wire            trp_end     ;   //预充电有效周期结束//reg   define
reg     [3:0]   write_state ;   //SDRAM写状态
reg     [9:0]   cnt_clk     ;   //时钟周期计数,记录写数据阶段各状态等待时间
reg             cnt_clk_rst ;   //时钟周期计数复位标志//wr_end:一次突发写结束
assign  wr_end = (write_state == WR_END) ? 1'b1 : 1'b0;//wr_ack:写SDRAM响应信号
assign  wr_ack = ( write_state == WR_WRITE) || ((write_state == WR_DATA) && (cnt_clk <= wr_burst_len - 2'd2));//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_clk <=  10'd0;else    if(cnt_clk_rst == 1'b1)cnt_clk <=  10'd0;elsecnt_clk <=  cnt_clk + 1'b1;//trcd_end,twrite_end,trp_end:等待结束标志
assign  trcd_end    =   ((write_state == WR_TRCD)&&(cnt_clk == TRCD_CLK        )) ? 1'b1 : 1'b0;    //激活周期结束
assign  twrite_end  =   ((write_state == WR_DATA)&&(cnt_clk == wr_burst_len - 1)) ? 1'b1 : 1'b0;    //突发写结束
assign  trp_end     =   ((write_state == WR_TRP )&&(cnt_clk == TRP_CLK         )) ? 1'b1 : 1'b0;    //预充电等待周期结束//write_state:SDRAM的工作状态机
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)write_state <=  WR_IDLE;elsecase(write_state)WR_IDLE:if((wr_en ==1'b1) && (init_end == 1'b1))write_state <=  WR_ACTIVE;elsewrite_state <=  write_state;WR_ACTIVE:write_state <=  WR_TRCD;WR_TRCD:if(trcd_end == 1'b1)write_state <=  WR_WRITE;elsewrite_state <=  write_state;WR_WRITE:write_state <=  WR_DATA;WR_DATA:if(twrite_end == 1'b1)write_state <=  WR_PRE;elsewrite_state <=  write_state;WR_PRE:write_state <=  WR_TRP;WR_TRP:if(trp_end == 1'b1)write_state <=  WR_END;elsewrite_state <=  write_state;WR_END:write_state <=  WR_IDLE;default:write_state <=  WR_IDLE;endcase//计数器控制逻辑
always@(*)begincase(write_state)WR_IDLE:    cnt_clk_rst   <=  1'b1;WR_TRCD:    cnt_clk_rst   <=  (trcd_end == 1'b1) ? 1'b1 : 1'b0;WR_WRITE:   cnt_clk_rst   <=  1'b1;WR_DATA:    cnt_clk_rst   <=  (twrite_end == 1'b1) ? 1'b1 : 1'b0;WR_TRP:     cnt_clk_rst   <=  (trp_end == 1'b1) ? 1'b1 : 1'b0;WR_END:     cnt_clk_rst   <=  1'b1;default:    cnt_clk_rst   <=  1'b0;endcaseend//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginwrite_cmd   <=  NOP;write_ba    <=  2'b11;write_addr  <=  13'h1fff;endelsecase(write_state)WR_IDLE,WR_TRCD,WR_TRP:beginwrite_cmd   <=  NOP;write_ba    <=  2'b11;write_addr  <=  13'h1fff;endWR_ACTIVE:  //激活指令beginwrite_cmd   <=  ACTIVE;write_ba    <=  wr_addr[23:22];write_addr  <=  wr_addr[21:9];endWR_WRITE:   //写操作指令beginwrite_cmd   <=  WRITE;write_ba    <=  wr_addr[23:22];write_addr  <=  {4'b0000,wr_addr[8:0]};end     WR_DATA:    //突发传输终止指令beginif(twrite_end == 1'b1)write_cmd <=  B_STOP;elsebeginwrite_cmd   <=  NOP;write_ba    <=  2'b11;write_addr  <=  13'h1fff;endendWR_PRE:     //预充电指令beginwrite_cmd   <= P_CHARGE;write_ba    <= wr_addr[23:22];write_addr  <= 13'h0400;endWR_END:beginwrite_cmd   <=  NOP;write_ba    <=  2'b11;write_addr  <=  13'h1fff;enddefault:beginwrite_cmd   <=  NOP;write_ba    <=  2'b11;write_addr  <=  13'h1fff;endendcase//wr_sdram_en:数据总线输出使能
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_sdram_en <=  1'b0;elsewr_sdram_en <=  wr_ack;//wr_sdram_data:写入SDRAM的数据
assign  wr_sdram_data = (wr_sdram_en == 1'b1) ? wr_data : 16'd0;endmodule

sdram_read

`timescale  1ns/1nsmodule  sdram_read
(input   wire            sys_clk         ,   //系统时钟,频率100MHzinput   wire            sys_rst_n       ,   //复位信号,低电平有效input   wire            init_end        ,   //初始化结束信号input   wire            rd_en           ,   //读使能input   wire    [23:0]  rd_addr         ,   //读SDRAM地址input   wire    [15:0]  rd_data         ,   //自SDRAM中读出的数据input   wire    [9:0]   rd_burst_len    ,   //读突发SDRAM字节数output  wire            rd_ack          ,   //读SDRAM响应信号output  wire            rd_end          ,   //一次突发读结束output  reg     [3:0]   read_cmd        ,   //读数据阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}output  reg     [1:0]   read_ba         ,   //读数据阶段Bank地址output  reg     [12:0]  read_addr       ,   //地址数据,辅助预充电操作,行、列地址,A12-A0,13位地址output  wire    [15:0]  rd_sdram_data       //SDRAM读出的数据
);//parameter     define
parameter   TRCD_CLK    =   10'd2   ,   //激活等待周期TCL_CLK     =   10'd3   ,   //潜伏期TRP_CLK     =   10'd2   ;   //预充电等待周期
parameter   RD_IDLE     =   4'b0000 ,   //空闲RD_ACTIVE   =   4'b0001 ,   //激活RD_TRCD     =   4'b0011 ,   //激活等待RD_READ     =   4'b0010 ,   //读操作RD_CL       =   4'b0100 ,   //潜伏期RD_DATA     =   4'b0101 ,   //读数据RD_PRE      =   4'b0111 ,   //预充电RD_TRP      =   4'b0110 ,   //预充电等待RD_END      =   4'b1100 ;   //一次突发读结束
parameter   NOP         =   4'b0111 ,   //空操作指令ACTIVE      =   4'b0011 ,   //激活指令READ        =   4'b0101 ,   //数据读指令B_STOP      =   4'b0110 ,   //突发停止指令P_CHARGE    =   4'b0010 ;   //预充电指令//wire  define
wire            trcd_end    ;   //激活等待周期结束
wire            trp_end     ;   //预充电等待周期结束
wire            tcl_end     ;   //潜伏期结束标志
wire            tread_end   ;   //突发读结束
wire            rdburst_end ;   //读突发终止//reg   define
reg     [3:0]   read_state  ;   //SDRAM写状态
reg     [9:0]   cnt_clk     ;   //时钟周期计数,记录初始化各状态等待时间
reg             cnt_clk_rst ;   //时钟周期计数复位标志
reg     [15:0]  rd_data_reg ;//rd_data_reg
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_data_reg <=  16'd0;elserd_data_reg <=  rd_data;//rd_end:一次突发读结束
assign  rd_end = (read_state == RD_END) ? 1'b1 : 1'b0;
//rd_ack:读SDRAM响应信号
assign  rd_ack = (read_state == RD_DATA) && (cnt_clk >= 10'd1) && (cnt_clk < (rd_burst_len + 2'd1));//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_clk <=  10'd0;else    if(cnt_clk_rst == 1'b1)cnt_clk <=  10'd0;elsecnt_clk <=  cnt_clk + 1'b1;//trcd_end,trp_end,tcl_end,tread_end,rdburst_end:等待结束标志
assign  trcd_end    =   ((read_state == RD_TRCD) && (cnt_clk == TRCD_CLK))         ? 1'b1 : 1'b0;    //行选通周期结束
assign  trp_end     =   ((read_state == RD_TRP ) && (cnt_clk == TRP_CLK))          ? 1'b1 : 1'b0;    //预充电有效周期结束
assign  tcl_end     =   ((read_state == RD_CL  ) && (cnt_clk == TCL_CLK - 1))      ? 1'b1 : 1'b0;    //潜伏期结束
assign  tread_end   =   ((read_state == RD_DATA) && (cnt_clk == rd_burst_len + 2)) ? 1'b1 : 1'b0;    //突发读结束
assign  rdburst_end =   ((read_state == RD_DATA) && (cnt_clk == rd_burst_len - 4)) ? 1'b1 : 1'b0;    //读突发终止//read_state:SDRAM的工作状态机
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)read_state  <=  RD_IDLE;elsecase(read_state)RD_IDLE:if((rd_en ==1'b1) && (init_end == 1'b1))read_state <=  RD_ACTIVE;elseread_state <=  RD_IDLE;RD_ACTIVE:read_state <=  RD_TRCD;RD_TRCD:if(trcd_end == 1'b1)read_state <=  RD_READ;elseread_state <=  RD_TRCD;RD_READ:read_state <=  RD_CL;RD_CL:read_state <=  (tcl_end == 1'b1) ? RD_DATA : RD_CL;RD_DATA:read_state <=  (tread_end == 1'b1) ? RD_PRE : RD_DATA;RD_PRE:read_state  <=  RD_TRP;RD_TRP:read_state  <=  (trp_end == 1'b1) ? RD_END : RD_TRP;RD_END:read_state  <=  RD_IDLE;default:read_state  <=  RD_IDLE;endcase//计数器控制逻辑
always@(*)begincase(read_state)RD_IDLE:    cnt_clk_rst   <=  1'b1;RD_TRCD:    cnt_clk_rst   <=  (trcd_end == 1'b1) ? 1'b1 : 1'b0;RD_READ:    cnt_clk_rst   <=  1'b1;RD_CL:      cnt_clk_rst   <=  (tcl_end == 1'b1) ? 1'b1 : 1'b0;RD_DATA:    cnt_clk_rst   <=  (tread_end == 1'b1) ? 1'b1 : 1'b0;RD_TRP:     cnt_clk_rst   <=  (trp_end == 1'b1) ? 1'b1 : 1'b0;RD_END:     cnt_clk_rst   <=  1'b1;default:    cnt_clk_rst   <=  1'b0;endcaseend//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginread_cmd    <=  NOP;read_ba     <=  2'b11;read_addr   <=  13'h1fff;endelsecase(read_state)RD_IDLE,RD_TRCD,RD_TRP:beginread_cmd    <=  NOP;read_ba     <=  2'b11;read_addr   <=  13'h1fff;endRD_ACTIVE:  //激活指令beginread_cmd    <=  ACTIVE;read_ba     <=  rd_addr[23:22];read_addr   <=  rd_addr[21:9];endRD_READ:    //读操作指令beginread_cmd    <=  READ;read_ba     <=  rd_addr[23:22];read_addr   <=  {4'b0000,rd_addr[8:0]};endRD_DATA:    //突发传输终止指令beginif(rdburst_end == 1'b1)read_cmd <=  B_STOP;elsebeginread_cmd    <=  NOP;read_ba     <=  2'b11;read_addr   <=  13'h1fff;endendRD_PRE:     //预充电指令beginread_cmd    <= P_CHARGE;read_ba     <= rd_addr[23:22];read_addr   <= 13'h0400;endRD_END:beginread_cmd    <=  NOP;read_ba     <=  2'b11;read_addr   <=  13'h1fff;enddefault:beginread_cmd    <=  NOP;read_ba     <=  2'b11;read_addr   <=  13'h1fff;endendcase//rd_sdram_data:SDRAM读出的数据
assign  rd_sdram_data = (rd_ack == 1'b1) ? rd_data_reg : 16'b0;endmodule

sdram_arbit

`timescale  1ns/1nsmodule  sdram_arbit
(input   wire            sys_clk     ,   //系统时钟input   wire            sys_rst_n   ,   //复位信号
//sdram_initinput   wire    [3:0]   init_cmd    ,   //初始化阶段命令input   wire            init_end    ,   //初始化结束标志input   wire    [1:0]   init_ba     ,   //初始化阶段Bank地址input   wire    [12:0]  init_addr   ,   //初始化阶段数据地址
//sdram_auto_refinput   wire            aref_req    ,   //自刷新请求input   wire            aref_end    ,   //自刷新结束input   wire    [3:0]   aref_cmd    ,   //自刷新阶段命令input   wire    [1:0]   aref_ba     ,   //自动刷新阶段Bank地址input   wire    [12:0]  aref_addr   ,   //自刷新阶段数据地址
//sdram_writeinput   wire            wr_req      ,   //写数据请求input   wire    [1:0]   wr_ba       ,   //写阶段Bank地址input   wire    [15:0]  wr_data     ,   //写入SDRAM的数据input   wire            wr_end      ,   //一次写结束信号input   wire    [3:0]   wr_cmd      ,   //写阶段命令input   wire    [12:0]  wr_addr     ,   //写阶段数据地址input   wire            wr_sdram_en ,
//sdram_readinput   wire            rd_req      ,   //读数据请求input   wire            rd_end      ,   //一次读结束input   wire    [3:0]   rd_cmd      ,   //读阶段命令input   wire    [12:0]  rd_addr     ,   //读阶段数据地址input   wire    [1:0]   rd_ba       ,   //读阶段Bank地址output  reg             aref_en     ,   //自刷新使能output  reg             wr_en       ,   //写数据使能output  reg             rd_en       ,   //读数据使能output  wire            sdram_cke   ,   //SDRAM时钟使能output  wire            sdram_cs_n  ,   //SDRAM片选信号output  wire            sdram_ras_n ,   //SDRAM行地址选通output  wire            sdram_cas_n ,   //SDRAM列地址选通output  wire            sdram_we_n  ,   //SDRAM写使能output  reg     [1:0]   sdram_ba    ,   //SDRAM Bank地址output  reg     [12:0]  sdram_addr  ,   //SDRAM地址总线inout   wire    [15:0]  sdram_dq        //SDRAM数据总线
);//parameter define
parameter   IDLE    =   5'b0_0001   ,   //初始状态ARBIT   =   5'b0_0010   ,   //仲裁状态AREF    =   5'b0_0100   ,   //自动刷新状态WRITE   =   5'b0_1000   ,   //写状态READ    =   5'b1_0000   ;   //读状态
parameter   CMD_NOP =   4'b0111     ;   //空操作指令//reg   define
reg     [3:0]   sdram_cmd   ;   //写入SDRAM命令
reg     [4:0]   state       ;   //状态机状态//state:状态机状态
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)state   <=  IDLE;else    case(state)IDLE:   if(init_end == 1'b1)state   <=  ARBIT;elsestate   <=  IDLE;ARBIT:  if(aref_req == 1'b1)state   <=  AREF;else    if(wr_req == 1'b1)state   <=  WRITE;else    if(rd_req == 1'b1)state   <=  READ;elsestate   <=  ARBIT;AREF:   if(aref_end == 1'b1)state   <=  ARBIT;elsestate   <=  AREF; WRITE:  if(wr_end == 1'b1)state   <=  ARBIT;elsestate   <=  WRITE;READ:   if(rd_end == 1'b1)state   <=  ARBIT;elsestate   <=  READ;default:state   <=  IDLE;endcase//aref_en:自动刷新使能
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)aref_en  <=  1'b0;else    if((state == ARBIT) && (aref_req == 1'b1))aref_en  <=  1'b1;else    if(aref_end == 1'b1)aref_en  <=  1'b0;//wr_en:写数据使能
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_en   <=  1'b0;else    if((state == ARBIT) && (aref_req == 1'b0) && (wr_req == 1'b1))wr_en   <=  1'b1;else    if(wr_end == 1'b1)wr_en   <=  1'b0;//rd_en:读数据使能
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_en   <=  1'b0;else    if((state == ARBIT) && (aref_req == 1'b0)  && (rd_req == 1'b1))rd_en   <=  1'b1;else    if(rd_end == 1'b1)rd_en   <=  1'b0;//sdram_cmd:写入SDRAM命令;sdram_ba:SDRAM Bank地址;sdram_addr:SDRAM地址总线
always@(*)case(state) IDLE: beginsdram_cmd   <=  init_cmd;sdram_ba    <=  init_ba;sdram_addr  <=  init_addr;endAREF: beginsdram_cmd   <=  aref_cmd;sdram_ba    <=  aref_ba;sdram_addr  <=  aref_addr;endWRITE: beginsdram_cmd   <=  wr_cmd;sdram_ba    <=  wr_ba;sdram_addr  <=  wr_addr;endREAD: beginsdram_cmd   <=  rd_cmd;sdram_ba    <=  rd_ba;sdram_addr  <=  rd_addr;enddefault: beginsdram_cmd   <=  CMD_NOP;sdram_ba    <=  2'b11;sdram_addr  <=  13'h1fff;endendcase//SDRAM时钟使能
assign  sdram_cke = 1'b1;
//SDRAM数据总线
assign  sdram_dq = (wr_sdram_en == 1'b1) ? wr_data : 16'bz;
//片选信号,行地址选通信号,列地址选通信号,写使能信号
assign  {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = sdram_cmd;endmodule

sdram_ctrl

`timescale  1ns/1nsmodule  sdram_ctrl
(input   wire            sys_clk         ,   //系统时钟input   wire            sys_rst_n       ,   //复位信号,低电平有效
//SDRAM写端口input   wire            sdram_wr_req    ,   //写SDRAM请求信号input   wire    [23:0]  sdram_wr_addr   ,   //SDRAM写操作的地址input   wire    [9:0]   wr_burst_len    ,   //写sdram时数据突发长度input   wire    [15:0]  sdram_data_in   ,   //写入SDRAM的数据output  wire            sdram_wr_ack    ,   //写SDRAM响应信号
//SDRAM读端口input   wire            sdram_rd_req    ,   //读SDRAM请求信号input   wire    [23:0]  sdram_rd_addr   ,   //SDRAM读操作的地址input   wire    [9:0]   rd_burst_len    ,   //读sdram时数据突发长度output  wire    [15:0]  sdram_data_out  ,   //从SDRAM读出的数据output  wire            init_end        ,   //SDRAM 初始化完成标志output  wire            sdram_rd_ack    ,   //读SDRAM响应信号
//FPGA与SDRAM硬件接口output  wire            sdram_cke       ,   // SDRAM 时钟有效信号output  wire            sdram_cs_n      ,   // SDRAM 片选信号output  wire            sdram_ras_n     ,   // SDRAM 行地址选通output  wire            sdram_cas_n     ,   // SDRAM 列地址选通output  wire            sdram_we_n      ,   // SDRAM 写使能output  wire    [1:0]   sdram_ba        ,   // SDRAM Bank地址output  wire    [12:0]  sdram_addr      ,   // SDRAM 地址总线inout   wire    [15:0]  sdram_dq            // SDRAM 数据总线
);//wire  define
//sdram_init
wire    [3:0]   init_cmd    ;   //初始化阶段写入sdram的指令
wire    [1:0]   init_ba     ;   //初始化阶段Bank地址
wire    [12:0]  init_addr   ;   //初始化阶段地址数据,辅助预充电操作
//sdram_a_ref
wire            aref_req    ;   //自动刷新请求
wire            aref_end    ;   //自动刷新结束标志
wire    [3:0]   aref_cmd    ;   //自动刷新阶段写入sdram的指令
wire    [1:0]   aref_ba     ;   //自动刷新阶段Bank地址
wire    [12:0]  aref_addr   ;   //地址数据,辅助预充电操作
wire            aref_en     ;   //自动刷新使能
//sdram_write
wire            wr_en       ;   //写使能
wire            wr_end      ;   //一次写结束信号
wire    [3:0]   write_cmd   ;   //写阶段命令
wire    [1:0]   write_ba    ;   //写数据阶段Bank地址
wire    [12:0]  write_addr  ;   //写阶段数据地址
wire            wr_sdram_en ;   //SDRAM写使能
wire    [15:0]  wr_sdram_data;  //写入SDRAM的数据
//sdram_read
wire            rd_en       ;   //读使能
wire            rd_end      ;   //一次突发读结束
wire    [3:0]   read_cmd    ;   //读数据阶段写入sdram的指令
wire    [1:0]   read_ba     ;   //读阶段Bank地址
wire    [12:0]  read_addr   ;   //读阶段数据地址//------------- sdram_init_inst -------------
sdram_init  sdram_init_inst
(.sys_clk    (sys_clk    ),  //系统时钟,频率100MHz.sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效.init_cmd   (init_cmd   ),  //初始化阶段写入sdram的指令.init_ba    (init_ba    ),  //初始化阶段Bank地址.init_addr  (init_addr  ),  //初始化阶段地址数据,辅助预充电操作.init_end   (init_end   )   //初始化结束信号
);//------------- sdram_arbit_inst -------------
sdram_arbit sdram_arbit_inst
(.sys_clk    (sys_clk        ),  //系统时钟.sys_rst_n  (sys_rst_n      ),  //复位信号
//sdram_init.init_cmd   (init_cmd       ),  //初始化阶段命令.init_end   (init_end       ),  //初始化结束标志.init_ba    (init_ba        ),  //初始化阶段Bank地址.init_addr  (init_addr      ),  //初始化阶段数据地址
//sdram_auto_ref.aref_req   (aref_req       ),  //自刷新请求.aref_end   (aref_end       ),  //自刷新结束.aref_cmd   (aref_cmd       ),  //自刷新阶段命令.aref_ba    (aref_ba        ),  //自动刷新阶段Bank地址.aref_addr  (aref_addr      ),  //自刷新阶段数据地址
//sdram_write.wr_req     (sdram_wr_req   ),  //写数据请求.wr_end     (wr_end         ),  //一次写结束信号.wr_cmd     (write_cmd      ),  //写阶段命令.wr_ba      (write_ba       ),  //写阶段Bank地址.wr_addr    (write_addr     ),  //写阶段数据地址.wr_sdram_en(wr_sdram_en    ),  //SDRAM写使能.wr_data    (wr_sdram_data  ),  //写入SDRAM的数据
//sdram_read.rd_req     (sdram_rd_req   ),  //读数据请求.rd_end     (rd_end         ),  //一次读结束.rd_cmd     (read_cmd       ),  //读阶段命令.rd_addr    (read_addr      ),  //读阶段数据地址.rd_ba      (read_ba        ),  //读阶段Bank地址.aref_en    (aref_en        ),  //自刷新使能.wr_en      (wr_en          ),  //写数据使能.rd_en      (rd_en          ),  //读数据使能.sdram_cke  (sdram_cke      ),  //SDRAM时钟使能.sdram_cs_n (sdram_cs_n     ),  //SDRAM片选信号.sdram_ras_n(sdram_ras_n    ),  //SDRAM行地址选通.sdram_cas_n(sdram_cas_n    ),  //SDRAM列地址选通.sdram_we_n (sdram_we_n     ),  //SDRAM写使能.sdram_ba   (sdram_ba       ),  //SDRAM Bank地址.sdram_addr (sdram_addr     ),  //SDRAM地址总线.sdram_dq   (sdram_dq       )   //SDRAM数据总线
);//------------- sdram_a_ref_inst -------------
sdram_a_ref sdram_a_ref_inst
(.sys_clk     (sys_clk   ),  //系统时钟,频率100MHz.sys_rst_n   (sys_rst_n ),  //复位信号,低电平有效.init_end    (init_end  ),  //初始化结束信号.aref_en     (aref_en   ),  //自动刷新使能.aref_req    (aref_req  ),  //自动刷新请求.aref_cmd    (aref_cmd  ),  //自动刷新阶段写入sdram的指令.aref_ba     (aref_ba   ),  //自动刷新阶段Bank地址.aref_addr   (aref_addr ),  //地址数据,辅助预充电操作.aref_end    (aref_end  )   //自动刷新结束标志
);//------------- sdram_write_inst -------------
sdram_write sdram_write_inst
(.sys_clk        (sys_clk        ),  //系统时钟,频率100MHz.sys_rst_n      (sys_rst_n      ),  //复位信号,低电平有效.init_end       (init_end       ),  //初始化结束信号.wr_en          (wr_en          ),  //写使能.wr_addr        (sdram_wr_addr  ),  //写SDRAM地址.wr_data        (sdram_data_in  ),  //待写入SDRAM的数据(写FIFO传入).wr_burst_len   (wr_burst_len   ),  //写突发SDRAM字节数.wr_ack         (sdram_wr_ack   ),  //写SDRAM响应信号.wr_end         (wr_end         ),  //一次突发写结束.write_cmd      (write_cmd      ),  //写数据阶段写入sdram的指令.write_ba       (write_ba       ),  //写数据阶段Bank地址.write_addr     (write_addr     ),  //地址数据,辅助预充电操作.wr_sdram_en    (wr_sdram_en    ),  //数据总线输出使能.wr_sdram_data  (wr_sdram_data  )   //写入SDRAM的数据
);//------------- sdram_read_inst -------------
sdram_read  sdram_read_inst
(.sys_clk        (sys_clk        ),  //系统时钟,频率100MHz.sys_rst_n      (sys_rst_n      ),  //复位信号,低电平有效.init_end       (init_end       ),  //初始化结束信号.rd_en          (rd_en          ),  //读使能.rd_addr        (sdram_rd_addr  ),  //读SDRAM地址.rd_data        (sdram_dq       ),  //自SDRAM中读出的数据.rd_burst_len   (rd_burst_len   ),  //读突发SDRAM字节数.rd_ack         (sdram_rd_ack   ),  //读SDRAM响应信号.rd_end         (rd_end         ),  //一次突发读结束.read_cmd       (read_cmd       ),  //读数据阶段写入sdram的指令.read_ba        (read_ba        ),  //读数据阶段Bank地址.read_addr      (read_addr      ),  //地址数据,辅助预充电操作.rd_sdram_data  (sdram_data_out )   //SDRAM读出的数据
);endmodule

2. sdram_top

fifo_ctrl

`timescale  1ns/1nsmodule  fifo_ctrl
(input   wire            sys_clk         ,   //系统时钟input   wire            sys_rst_n       ,   //复位信号
//写fifo信号input   wire            wr_fifo_wr_clk  ,   //写FIFO写时钟input   wire            wr_fifo_wr_req  ,   //写FIFO写请求input   wire    [15:0]  wr_fifo_wr_data ,   //写FIFO写数据input   wire    [23:0]  sdram_wr_b_addr ,   //写SDRAM首地址input   wire    [23:0]  sdram_wr_e_addr ,   //写SDRAM末地址input   wire    [9:0]   wr_burst_len    ,   //写SDRAM数据突发长度input   wire            wr_rst          ,   //写复位信号
//读fifo信号input   wire            rd_fifo_rd_clk  ,   //读FIFO读时钟input   wire            rd_fifo_rd_req  ,   //读FIFO读请求input   wire    [23:0]  sdram_rd_b_addr ,   //读SDRAM首地址input   wire    [23:0]  sdram_rd_e_addr ,   //读SDRAM末地址input   wire    [9:0]   rd_burst_len    ,   //读SDRAM数据突发长度input   wire            rd_rst          ,   //读复位信号output  wire    [15:0]  rd_fifo_rd_data ,   //读FIFO读数据output  wire    [9:0]   rd_fifo_num     ,   //读fifo中的数据量input   wire            read_valid      ,   //SDRAM读使能input   wire            init_end        ,   //SDRAM初始化完成标志
//SDRAM写信号input   wire            sdram_wr_ack    ,   //SDRAM写响应output  reg             sdram_wr_req    ,   //SDRAM写请求output  reg     [23:0]  sdram_wr_addr   ,   //SDRAM写地址output  wire    [15:0]  sdram_data_in   ,   //写入SDRAM的数据
//SDRAM读信号input   wire            sdram_rd_ack    ,   //SDRAM读相应input   wire    [15:0]  sdram_data_out  ,   //读出SDRAM数据output  reg             sdram_rd_req    ,   //SDRAM读请求output  reg     [23:0]  sdram_rd_addr       //SDRAM读地址
);//wire define
wire            wr_ack_fall ;   //写响应信号下降沿
wire            rd_ack_fall ;   //读相应信号下降沿
wire    [9:0]   wr_fifo_num ;   //写fifo中的数据量//reg define
reg        wr_ack_dly       ;   //写响应打拍
reg        rd_ack_dly       ;   //读响应打拍//wr_ack_dly:写响应信号打拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_ack_dly  <=  1'b0;elsewr_ack_dly  <=  sdram_wr_ack;//rd_ack_dly:读响应信号打拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_ack_dly  <=  1'b0;elserd_ack_dly <=  sdram_rd_ack;//wr_ack_fall,rd_ack_fall:检测读写响应信号下降沿
assign  wr_ack_fall = (wr_ack_dly & ~sdram_wr_ack);
assign  rd_ack_fall = (rd_ack_dly & ~sdram_rd_ack);//sdram_wr_addr:sdram写地址
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)sdram_wr_addr   <=  24'd0;else    if(wr_rst == 1'b1)sdram_wr_addr   <=  sdram_wr_b_addr;else    if(wr_ack_fall == 1'b1) //一次突发写结束,更改写地址beginif(sdram_wr_addr < (sdram_wr_e_addr - wr_burst_len))//不使用乒乓操作,一次突发写结束,更改写地址,未达到末地址,写地址累加sdram_wr_addr   <=  sdram_wr_addr + wr_burst_len;else        //不使用乒乓操作,到达末地址,回到写起始地址sdram_wr_addr   <=  sdram_wr_b_addr;end//sdram_rd_addr:sdram读地址
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)sdram_rd_addr   <=  24'd0;else    if(rd_rst == 1'b1)sdram_rd_addr   <=  sdram_rd_b_addr;else    if(rd_ack_fall == 1'b1) //一次突发读结束,更改读地址beginif(sdram_rd_addr < (sdram_rd_e_addr - rd_burst_len))//读地址未达到末地址,读地址累加sdram_rd_addr   <=  sdram_rd_addr + rd_burst_len;else    //到达末地址,回到首地址sdram_rd_addr   <=  sdram_rd_b_addr;end//sdram_wr_req,sdram_rd_req:读写请求信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginsdram_wr_req    <=  1'b0;sdram_rd_req    <=  1'b0;endelse    if(init_end == 1'b1)   //初始化完成后响应读写请求begin   //优先执行写操作,防止写入SDRAM中的数据丢失if(wr_fifo_num >= wr_burst_len)begin   //写FIFO中的数据量达到写突发长度sdram_wr_req    <=  1'b1;   //写请求有效sdram_rd_req    <=  1'b0;endelse    if((rd_fifo_num < rd_burst_len) && (read_valid == 1'b1))begin //读FIFO中的数据量小于读突发长度,且读使能信号有效sdram_wr_req    <=  1'b0;sdram_rd_req    <=  1'b1;   //读请求有效endelsebeginsdram_wr_req    <=  1'b0;sdram_rd_req    <=  1'b0;endendelsebeginsdram_wr_req    <=  1'b0;sdram_rd_req    <=  1'b0;end//------------- wr_fifo_data -------------
fifo_data   wr_fifo_data(//用户接口.wrclk      (wr_fifo_wr_clk ),  //写时钟.wrreq      (wr_fifo_wr_req ),  //写请求.data       (wr_fifo_wr_data),  //写数据//SDRAM接口.rdclk      (sys_clk        ),  //读时钟.rdreq      (sdram_wr_ack   ),  //读请求.q          (sdram_data_in  ),  //读数据.rdusedw    (wr_fifo_num    ),  //FIFO中的数据量.wrusedw    (               ),.aclr       (~sys_rst_n || wr_rst)  //清零信号);//------------- rd_fifo_data -------------
fifo_data   rd_fifo_data(//sdram接口.wrclk      (sys_clk        ),  //写时钟.wrreq      (sdram_rd_ack   ),  //写请求.data       (sdram_data_out ),  //写数据//用户接口.rdclk      (rd_fifo_rd_clk ),  //读时钟.rdreq      (rd_fifo_rd_req ),  //读请求.q          (rd_fifo_rd_data),  //读数据.rdusedw    (               ),.wrusedw    (rd_fifo_num    ),  //FIFO中的数据量.aclr       (~sys_rst_n || rd_rst)  //清零信号);endmodule

sdram_top

`timescale  1ns/1nsmodule  sdram_top
(input   wire            sys_clk         ,   //系统时钟input   wire            clk_out         ,   //相位偏移时钟input   wire            sys_rst_n       ,   //复位信号,低有效
//写FIFO信号input   wire            wr_fifo_wr_clk  ,   //写FIFO写时钟input   wire            wr_fifo_wr_req  ,   //写FIFO写请求input   wire    [15:0]  wr_fifo_wr_data ,   //写FIFO写数据input   wire    [23:0]  sdram_wr_b_addr ,   //写SDRAM首地址input   wire    [23:0]  sdram_wr_e_addr ,   //写SDRAM末地址input   wire    [9:0]   wr_burst_len    ,   //写SDRAM数据突发长度input   wire            wr_rst          ,   //写复位信号
//读FIFO信号input   wire            rd_fifo_rd_clk  ,   //读FIFO读时钟input   wire            rd_fifo_rd_req  ,   //读FIFO读请求input   wire    [23:0]  sdram_rd_b_addr ,   //读SDRAM首地址input   wire    [23:0]  sdram_rd_e_addr ,   //读SDRAM末地址input   wire    [9:0]   rd_burst_len    ,   //读SDRAM数据突发长度input   wire            rd_rst          ,   //读复位信号output  wire    [15:0]  rd_fifo_rd_data ,   //读FIFO读数据output  wire    [9:0]   rd_fifo_num     ,   //读fifo中的数据量input   wire            read_valid      ,   //SDRAM读使能output  wire            init_end        ,   //SDRAM初始化完成标志
//SDRAM接口信号output  wire            sdram_clk       ,   //SDRAM芯片时钟output  wire            sdram_cke       ,   //SDRAM时钟有效信号output  wire            sdram_cs_n      ,   //SDRAM片选信号output  wire            sdram_ras_n     ,   //SDRAM行地址选通脉冲output  wire            sdram_cas_n     ,   //SDRAM列地址选通脉冲output  wire            sdram_we_n      ,   //SDRAM写允许位output  wire    [1:0]   sdram_ba        ,   //SDRAM的L-Bank地址线output  wire    [12:0]  sdram_addr      ,   //SDRAM地址总线output  wire    [1:0]   sdram_dqm       ,   //SDRAM数据掩码inout   wire    [15:0]  sdram_dq            //SDRAM数据总线
);//wire  define
wire            sdram_wr_req    ;   //sdram 写请求
wire            sdram_wr_ack    ;   //sdram 写响应
wire    [23:0]  sdram_wr_addr   ;   //sdram 写地址
wire    [15:0]  sdram_data_in   ;   //写入sdram中的数据wire            sdram_rd_req    ;   //sdram 读请求
wire            sdram_rd_ack    ;   //sdram 读响应
wire    [23:0]  sdram_rd_addr   ;   //sdram 读地址
wire    [15:0]  sdram_data_out  ;   //从sdram中读出的数据//sdram_clk:SDRAM芯片时钟
assign  sdram_clk = clk_out;
//sdram_dqm:SDRAM数据掩码
assign  sdram_dqm = 2'b00;//------------- fifo_ctrl_inst -------------
fifo_ctrl   fifo_ctrl_inst(//system    signal.sys_clk        (sys_clk        ),  //SDRAM控制时钟.sys_rst_n      (sys_rst_n      ),  //复位信号
//write fifo signal.wr_fifo_wr_clk (wr_fifo_wr_clk ),  //写FIFO写时钟.wr_fifo_wr_req (wr_fifo_wr_req ),  //写FIFO写请求.wr_fifo_wr_data(wr_fifo_wr_data),  //写FIFO写数据.sdram_wr_b_addr(sdram_wr_b_addr),  //写SDRAM首地址.sdram_wr_e_addr(sdram_wr_e_addr),  //写SDRAM末地址.wr_burst_len   (wr_burst_len   ),  //写SDRAM数据突发长度.wr_rst         (wr_rst         ),  //写清零信号
//read fifo signal.rd_fifo_rd_clk (rd_fifo_rd_clk ),  //读FIFO读时钟.rd_fifo_rd_req (rd_fifo_rd_req ),  //读FIFO读请求.rd_fifo_rd_data(rd_fifo_rd_data),  //读FIFO读数据.rd_fifo_num    (rd_fifo_num    ),  //读FIFO中的数据量.sdram_rd_b_addr(sdram_rd_b_addr),  //读SDRAM首地址.sdram_rd_e_addr(sdram_rd_e_addr),  //读SDRAM末地址.rd_burst_len   (rd_burst_len   ),  //读SDRAM数据突发长度.rd_rst         (rd_rst         ),  //读清零信号
//USER ctrl signal.read_valid     (read_valid     ),  //SDRAM读使能.init_end       (init_end       ),  //SDRAM初始化完成标志
//SDRAM ctrl of write.sdram_wr_ack   (sdram_wr_ack   ),  //SDRAM写响应.sdram_wr_req   (sdram_wr_req   ),  //SDRAM写请求.sdram_wr_addr  (sdram_wr_addr  ),  //SDRAM写地址.sdram_data_in  (sdram_data_in  ),  //写入SDRAM的数据
//SDRAM ctrl of read.sdram_rd_ack   (sdram_rd_ack   ),  //SDRAM读请求.sdram_data_out (sdram_data_out ),  //SDRAM读响应.sdram_rd_req   (sdram_rd_req   ),  //SDRAM读地址.sdram_rd_addr  (sdram_rd_addr  )  //读出SDRAM数据
);//------------- sdram_ctrl_inst -------------
sdram_ctrl  sdram_ctrl_inst(.sys_clk        (sys_clk        ),   //系统时钟.sys_rst_n      (sys_rst_n      ),   //复位信号,低电平有效
//SDRAM 控制器写端口.sdram_wr_req   (sdram_wr_req   ),   //写SDRAM请求信号.sdram_wr_addr  (sdram_wr_addr  ),   //SDRAM写操作的地址.wr_burst_len   (wr_burst_len   ),   //写sdram时数据突发长度.sdram_data_in  (sdram_data_in  ),   //写入SDRAM的数据.sdram_wr_ack   (sdram_wr_ack   ),   //写SDRAM响应信号
//SDRAM 控制器读端口.sdram_rd_req   (sdram_rd_req   ),  //读SDRAM请求信号.sdram_rd_addr  (sdram_rd_addr  ),  //SDRAM写操作的地址.rd_burst_len   (rd_burst_len   ),  //读sdram时数据突发长度.sdram_data_out (sdram_data_out ),  //从SDRAM读出的数据.init_end       (init_end       ),  //SDRAM 初始化完成标志.sdram_rd_ack   (sdram_rd_ack   ),  //读SDRAM响应信号
//FPGA与SDRAM硬件接口.sdram_cke      (sdram_cke      ),  // SDRAM 时钟有效信号.sdram_cs_n     (sdram_cs_n     ),  // SDRAM 片选信号.sdram_ras_n    (sdram_ras_n    ),  // SDRAM 行地址选通脉冲.sdram_cas_n    (sdram_cas_n    ),  // SDRAM 列地址选通脉冲.sdram_we_n     (sdram_we_n     ),  // SDRAM 写允许位.sdram_ba       (sdram_ba       ),  // SDRAM L-Bank地址线.sdram_addr     (sdram_addr     ),  // SDRAM 地址总线.sdram_dq       (sdram_dq       )   // SDRAM 数据总线
);endmodule

3. uart_sdram

uart_rx

`timescale  1ns/1nsmodule  uart_rx
#(parameter   UART_BPS    =   'd9600,         //串口波特率parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(input   wire            sys_clk     ,   //系统时钟50MHzinput   wire            sys_rst_n   ,   //全局复位input   wire            rx          ,   //串口接收数据output  reg     [7:0]   po_data     ,   //串转并后的8bit数据output  reg             po_flag         //串转并后的数据有效标志信号
);//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;//reg   define
reg         rx_reg1     ;
reg         rx_reg2     ;
reg         rx_reg3     ;
reg         start_nedge ;
reg         work_en     ;
reg [12:0]  baud_cnt    ;
reg         bit_flag    ;
reg [3:0]   bit_cnt     ;
reg [7:0]   rx_data     ;
reg         rx_flag     ;//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rx_reg1 <= 1'b1;elserx_reg1 <= rx;//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rx_reg2 <= 1'b1;elserx_reg2 <= rx_reg1;//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rx_reg3 <= 1'b1;elserx_reg3 <= rx_reg2;//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)start_nedge <= 1'b0;else    if((~rx_reg2) && (rx_reg3))start_nedge <= 1'b1;elsestart_nedge <= 1'b0;//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)work_en <= 1'b0;else    if(start_nedge == 1'b1)work_en <= 1'b1;else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))work_en <= 1'b0;//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)baud_cnt <= 13'b0;else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))baud_cnt <= 13'b0;else    if(work_en == 1'b1)baud_cnt <= baud_cnt + 1'b1;//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)bit_flag <= 1'b0;else    if(baud_cnt == BAUD_CNT_MAX/2 - 1)bit_flag <= 1'b1;elsebit_flag <= 1'b0;//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)bit_cnt <= 4'b0;else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))bit_cnt <= 4'b0;else    if(bit_flag ==1'b1)bit_cnt <= bit_cnt + 1'b1;//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rx_data <= 8'b0;else    if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))rx_data <= {rx_reg3, rx_data[7:1]};//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rx_flag <= 1'b0;else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))rx_flag <= 1'b1;elserx_flag <= 1'b0;//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)po_data <= 8'b0;else    if(rx_flag == 1'b1)po_data <= rx_data;//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)po_flag <= 1'b0;elsepo_flag <= rx_flag;endmodule

uart_tx

`timescale  1ns/1nsmodule  uart_tx
#(parameter   UART_BPS    =   'd9600,         //串口波特率parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(input   wire            sys_clk     ,   //系统时钟50MHzinput   wire            sys_rst_n   ,   //全局复位input   wire    [7:0]   pi_data     ,   //模块输入的8bit数据input   wire            pi_flag     ,   //并行数据有效标志信号output  reg             tx              //串转并后的1bit数据
);//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;//reg   define
reg [12:0]  baud_cnt;
reg         bit_flag;
reg [3:0]   bit_cnt ;
reg         work_en ;//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)work_en <= 1'b0;else    if(pi_flag == 1'b1)work_en <= 1'b1;else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))work_en <= 1'b0;//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)baud_cnt <= 13'b0;else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))baud_cnt <= 13'b0;else    if(work_en == 1'b1)baud_cnt <= baud_cnt + 1'b1;//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)bit_flag <= 1'b0;else    if(baud_cnt == 13'd1)bit_flag <= 1'b1;elsebit_flag <= 1'b0;//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)bit_cnt <= 4'b0;else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))bit_cnt <= 4'b0;else    if((bit_flag == 1'b1) && (work_en == 1'b1))bit_cnt <= bit_cnt + 1'b1;//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)tx <= 1'b1; //空闲状态时为高电平else    if(bit_flag == 1'b1)case(bit_cnt)0       : tx <= 1'b0;1       : tx <= pi_data[0];2       : tx <= pi_data[1];3       : tx <= pi_data[2];4       : tx <= pi_data[3];5       : tx <= pi_data[4];6       : tx <= pi_data[5];7       : tx <= pi_data[6];8       : tx <= pi_data[7];9       : tx <= 1'b1;default : tx <= 1'b1;endcaseendmodule

fifo_read

`timescale  1ns/1nsmodule  fifo_read
(input   wire            sys_clk     ,   //系统时钟,频率50MHzinput   wire            sys_rst_n   ,   //复位信号,低电平有效input   wire    [9:0]   rd_fifo_num ,   //SDRAM中读fifo中数据个数input   wire    [7:0]   pi_data     ,   //读出数据input   wire    [9:0]   burst_num   ,   //一次突发数据个数output  reg             read_en     ,   //SDRAM中读fifo的读使能output  wire    [7:0]   tx_data     ,   //输出数据output  reg             tx_flag         //输出数据标志信号
);//parameter define
parameter   BAUD_CNT_END        =   13'd5207        ,BAUD_CNT_END_HALF   =   13'd2603        ;
parameter   CNT_WAIT_MAX        =   24'd4_999_999   ;//wire  define
wire    [9:0]   data_num    ;   //fifo中数据个数//reg   define
reg         read_en_dly     ;
reg [12:0]  baud_cnt        ;
reg         rd_en           ;
reg         rd_flag         ;
reg [9:0]   cnt_read        ;
reg [3:0]   bit_cnt         ;
reg         bit_flag        ;//read_en:SDRAM中读fifo的读使能
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)read_en   <=  1'b0;else    if(rd_fifo_num == burst_num)read_en   <=  1'b1;else    if(data_num == burst_num - 2)read_en   <=  1'b0;//read_en_dly:SDRAM中读fifo的读使能打拍
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)read_en_dly    <=  1'b0;elseread_en_dly    <=  read_en;//rd_flag:向tx模块发送数据使能
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_flag <=  1'b0;else    if(cnt_read == burst_num)rd_flag <=  1'b0;else    if(data_num == burst_num)rd_flag <=  1'b1;//baud_cnt:波特率计数器计数从0计数到BAUD_CNT_END
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)baud_cnt    <=  13'd0;else    if(baud_cnt == BAUD_CNT_END)baud_cnt    <=  13'd0;else    if(rd_flag == 1'b1)baud_cnt    <=  baud_cnt + 1'b1;//bit_flag:bit计数器计数使能
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)bit_flag    <=  1'b0;else    if(baud_cnt == BAUD_CNT_END_HALF)bit_flag    <=  1'b1;elsebit_flag    <=  1'b0;//bit_cnt:bit计数器
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)bit_cnt <=  4'b0;else    if((bit_cnt == 4'd9) && (bit_flag == 1'b1))bit_cnt <=  4'b0;else    if(bit_flag ==  1'b1)bit_cnt <=  bit_cnt +   1'b1;//rd_en:读fifo的读使能
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_en   <=  1'b0;else    if(bit_cnt == 4'd9 && bit_flag == 1'b1)rd_en   <=  1'b1;elserd_en   <=  1'b0;//cnt_read:读出数据计数
always@(posedge sys_clk or  negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_read    <=  10'd0;else    if(cnt_read == burst_num)cnt_read    <=  10'b0;else    if(rd_en == 1'b1)cnt_read    <=  cnt_read + 1'b1;elsecnt_read    <=  cnt_read;//tx_flag:读出数据标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)tx_flag <=  1'b0;elsetx_flag <=  rd_en;//-------------fifo_read_inst--------------
read_fifo   read_fifo_inst(.clock  (sys_clk        ),  //input clk.data   (pi_data        ),  //input [7 : 0] din.wrreq  (read_en_dly    ),  //input wr_en.rdreq  (rd_en          ),  //input rd_en.q      (tx_data        ),  //output [7 : 0] dout.usedw  (data_num       )
);endmodule

uart_sdram

`timescale  1ns/1nsmodule  uart_sdram
(input   wire            sys_clk     ,   //时钟信号input   wire            sys_rst_n   ,   //复位信号input   wire            rx          ,   //串口接收数据output  wire            tx          ,   //串口发送数据output  wire            sdram_clk   ,   //SDRAM 芯片时钟output  wire            sdram_cke   ,   //SDRAM 时钟有效output  wire            sdram_cs_n  ,   //SDRAM 片选output  wire            sdram_cas_n ,   //SDRAM 行有效output  wire            sdram_ras_n ,   //SDRAM 列有效output  wire            sdram_we_n  ,   //SDRAM 写有效output  wire    [1:0]   sdram_ba    ,   //SDRAM Bank地址output  wire    [12:0]  sdram_addr  ,   //SDRAM 行/列地址output  wire    [1:0]   sdram_dqm   ,   //SDRAM 数据掩码inout   wire    [15:0]  sdram_dq        //SDRAM 数据
);//parameter define
parameter   DATA_NUM    =   24'd10          ;   //写入SDRAM数据个数
parameter   WAIT_MAX    =   16'd750         ;   //等待计数最大值
parameter   UART_BPS    =   14'd9600        ,   //比特率CLK_FREQ    =   26'd50_000_000  ;   //时钟频率// wire define
//uart_rx
wire    [ 7:0]  rx_data         ;   //串口接收模块拼接后的8位数据
wire            rx_flag         ;   //数据标志信号//fifo_read
wire    [ 7:0]  rfifo_wr_data   ;   //读fifo发热写入数据
wire            rfifo_wr_en     ;   //读fifo的写使能
wire    [ 7:0]  rfifo_rd_data   ;   //读fifo的读数据
wire            rfifo_rd_en     ;   //读fifo的读使能
wire    [9:0]   rd_fifo_num     ;   //读fifo中的数据量//clk_gen
wire            clk_50m         ;
wire            clk_100m        ;
wire            clk_100m_shift  ;   //pll产生时钟
wire            locked          ;   //pll锁定信号
wire            rst_n           ;   //复位信号//sdram_top_inst
reg     [23:0]  data_num        ;   //写入SDRAM数据个数计数
reg             read_valid      ;   //数据读使能
reg     [15:0]  cnt_wait        ;   //等待计数器//rst_n:复位信号
assign  rst_n = sys_rst_n & locked;//data_num:写入SDRAM数据个数计数
always@(posedge clk_50m or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_num    <=  24'd0;else    if(read_valid == 1'b1)data_num    <=  24'd0;else    if(rx_flag == 1'b1)data_num    <=  data_num + 1'b1;elsedata_num    <=  data_num;//cnt_wait:等待计数器
always@(posedge clk_50m or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_wait    <=  16'd0;else    if(cnt_wait == WAIT_MAX)cnt_wait    <=  16'd0;else    if(data_num == DATA_NUM)cnt_wait    <=  cnt_wait + 1'b1;//read_valid:数据读使能
always@(posedge clk_50m or negedge sys_rst_n)if(sys_rst_n == 1'b0)read_valid  <=  1'b0;else    if(cnt_wait == WAIT_MAX)read_valid  <=  1'b1;else    if(rd_fifo_num == DATA_NUM)read_valid  <=  1'b0;//------------- clk_gen_inst -------------
clk_gen clk_gen_inst (.inclk0     (sys_clk        ),.areset     (~sys_rst_n     ),.c0         (clk_50m        ),.c1         (clk_100m       ),.c2         (clk_100m_shift ),.locked     (locked         )
);//-------------uart_rx_inst-------------
uart_rx
#(.UART_BPS    (UART_BPS ),   //串口波特率.CLK_FREQ    (CLK_FREQ )    //时钟频率
)
uart_rx_inst
(.sys_clk     (clk_50m  ),   //input             sys_clk.sys_rst_n   (rst_n    ),   //input             sys_rst_n.rx          (rx       ),   //input             rx.po_data     (rx_data  ),   //output    [7:0]   rx_data.po_flag     (rx_flag  )    //output            rx_flag
);//------------- sdram_top_inst -------------
sdram_top   sdram_top_inst
(.sys_clk            (clk_100m       ),  //sdram 控制器参考时钟.clk_out            (clk_100m_shift ),  //用于输出的相位偏移时钟.sys_rst_n          (rst_n          ),  //系统复位
//用户写端口.wr_fifo_wr_clk     (clk_50m        ),  //写端口FIFO: 写时钟.wr_fifo_wr_req     (rx_flag        ),  //写端口FIFO: 写使能.wr_fifo_wr_data    ({8'b0,rx_data} ),  //写端口FIFO: 写数据.sdram_wr_b_addr    (24'd0          ),  //写SDRAM的起始地址.sdram_wr_e_addr    (DATA_NUM       ),  //写SDRAM的结束地址.wr_burst_len       (DATA_NUM       ),  //写SDRAM时的数据突发长度.wr_rst             (               ),  //写复位
//用户读端口.rd_fifo_rd_clk     (clk_50m        ),  //读端口FIFO: 读时钟.rd_fifo_rd_req     (rfifo_wr_en    ),  //读端口FIFO: 读使能.rd_fifo_rd_data    (rfifo_wr_data  ),  //读端口FIFO: 读数据.sdram_rd_b_addr    (24'd0          ),  //读SDRAM的起始地址.sdram_rd_e_addr    (DATA_NUM       ),  //读SDRAM的结束地址.rd_burst_len       (DATA_NUM       ),  //从SDRAM中读数据时的突发长度.rd_rst             (               ),  //读复位.rd_fifo_num        (rd_fifo_num    ),   //读fifo中的数据量
//用户控制端口.read_valid         (read_valid     ),  //SDRAM 读使能.init_end           (               ),  //SDRAM 初始化完成标志
//SDRAM 芯片接口.sdram_clk          (sdram_clk      ),  //SDRAM 芯片时钟.sdram_cke          (sdram_cke      ),  //SDRAM 时钟有效.sdram_cs_n         (sdram_cs_n     ),  //SDRAM 片选.sdram_ras_n        (sdram_ras_n    ),  //SDRAM 行有效.sdram_cas_n        (sdram_cas_n    ),  //SDRAM 列有效.sdram_we_n         (sdram_we_n     ),  //SDRAM 写有效.sdram_ba           (sdram_ba       ),  //SDRAM Bank地址.sdram_addr         (sdram_addr     ),  //SDRAM 行/列地址.sdram_dq           (sdram_dq       ),  //SDRAM 数据.sdram_dqm          (sdram_dqm      )   //SDRAM 数据掩码
);//------------- fifo_read_inst --------------
fifo_read   fifo_read_inst
(.sys_clk     (clk_50m       ),   //input             sys_clk.sys_rst_n   (sys_rst_n     ),   //input             sys_rst_n.rd_fifo_num (rd_fifo_num   ),.pi_data     (rfifo_wr_data ),   //input     [7:0]   pi_data.burst_num   (DATA_NUM      ),.read_en     (rfifo_wr_en   ),   //input             pi_flag.tx_data     (rfifo_rd_data ),   //output    [7:0]   tx_data.tx_flag     (rfifo_rd_en   )    //output            tx_flag
);//-------------uart_tx_inst-------------
uart_tx
#(.UART_BPS    (UART_BPS      ),  //串口波特率.CLK_FREQ    (CLK_FREQ      )   //时钟频率
)
uart_tx_inst
(.sys_clk     (sys_clk       ),   //input         sys_clk.sys_rst_n   (sys_rst_n     ),   //input         sys_rst_n.pi_data     (rfifo_rd_data ),   //input [7:0]   pi_data.pi_flag     (rfifo_rd_en   ),   //input         pi_flag.tx          (tx            )    //output        tx
);endmodule

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...