目的:对SDRAM进行读写测试,使用FIFO对SDRAM进行封装。

SDRAM功能框图:

SDRAM原理图:

初始化状态机:

工作状态机:

代码如下:

SDRAM顶层模块:连接外部芯片与测试灯,并通过pll例化三个时钟,供fifo(50)与SDRAM(100)控制模块使用,测试读写SDRAM数据的一致性。输出到SDRAM芯片的时钟为(100m_shift).


module sdram_rw_test(input         clk,                      //FPGA外部时钟,50Minput         rst_n,                    //按键复位,低电平有效//SDRAM 芯片接口output        sdram_clk,                //SDRAM 芯片时钟output        sdram_cke,                //SDRAM 时钟有效output        sdram_cs_n,               //SDRAM 片选output        sdram_ras_n,              //SDRAM 行有效output        sdram_cas_n,              //SDRAM 列有效output        sdram_we_n,               //SDRAM 写有效output [ 1:0] sdram_ba,                 //SDRAM Bank地址output [12:0] sdram_addr,               //SDRAM 行/列地址inout  [15:0] sdram_data,               //SDRAM 数据output [ 1:0] sdram_dqm,                //SDRAM 数据掩码//LEDoutput        led                       //状态指示灯);//wire define
wire        clk_50m;                        //SDRAM 读写测试时钟
wire        clk_100m;                       //SDRAM 控制器时钟
wire        clk_100m_shift;                 //相位偏移时钟wire        wr_en;                          //SDRAM 写端口:写使能
wire [15:0] wr_data;                        //SDRAM 写端口:写入的数据
wire        rd_en;                          //SDRAM 读端口:读使能
wire [15:0] rd_data;                        //SDRAM 读端口:读出的数据
wire        sdram_init_done;                //SDRAM 初始化完成信号wire        locked;                         //PLL输出有效标志
wire        sys_rst_n;                      //系统复位信号
wire        error_flag;                     //读写测试错误标志//*****************************************************
//**                    main code
//***************************************************** //待PLL输出稳定之后,停止系统复位
assign sys_rst_n = rst_n & locked;//例化PLL, 产生各模块所需要的时钟
pll_clk u_pll_clk(.inclk0             (clk),.areset             (~rst_n),.c0                 (clk_50m),.c1                 (clk_100m),.c2                 (clk_100m_shift),.locked             (locked));//SDRAM测试模块,对SDRAM进行读写测试
sdram_test u_sdram_test(.clk_50m            (clk_50m),.rst_n              (sys_rst_n),.wr_en              (wr_en),.wr_data            (wr_data),.rd_en              (rd_en),.rd_data            (rd_data),   .sdram_init_done    (sdram_init_done),    .error_flag         (error_flag));//利用LED灯指示SDRAM读写测试的结果
led_disp u_led_disp(.clk_50m            (clk_50m),.rst_n              (sys_rst_n),.error_flag         (error_flag),.led                (led)             );//SDRAM 控制器顶层模块,封装成FIFO接口
//SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
sdram_top u_sdram_top(.ref_clk          (clk_100m),         //sdram 控制器参考时钟.out_clk         (clk_100m_shift),   //用于输出的相位偏移时钟.rst_n             (sys_rst_n),        //系统复位//用户写端口.wr_clk            (clk_50m),          //写端口FIFO: 写时钟.wr_en                (wr_en),            //写端口FIFO: 写使能.wr_data          (wr_data),          //写端口FIFO: 写数据.wr_min_addr      (24'd0),           //写SDRAM的起始地址.wr_max_addr       (24'd1024),            //写SDRAM的结束地址.wr_len                (10'd512),         //写SDRAM时的数据突发长度.wr_load            (~sys_rst_n),       //写端口复位: 复位写地址,清空写FIFO//用户读端口.rd_clk            (clk_50m),          //读端口FIFO: 读时钟.rd_en                (rd_en),            //读端口FIFO: 读使能.rd_data          (rd_data),          //读端口FIFO: 读数据.rd_min_addr      (24'd0),           //读SDRAM的起始地址.rd_max_addr       (24'd1024),            //读SDRAM的结束地址.rd_len            (10'd512),         //从SDRAM中读数据时的突发长度.rd_load          (~sys_rst_n),       //读端口复位: 复位读地址,清空读FIFO//用户控制端口  .sdram_read_valid   (1'b1),             //SDRAM 读使能.sdram_init_done    (sdram_init_done),  //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_data            (sdram_data),       //SDRAM 数据.sdram_dqm            (sdram_dqm)         //SDRAM 数据掩码);endmodule 

SDRAM读写测试模块:测试写入SDRAM的数据,再将数据读出,数据是否发生改变。


module sdram_test(input             clk_50m,          //时钟input             rst_n,            //复位,低有效output reg        wr_en,            //SDRAM 写使能output reg [15:0] wr_data,          //SDRAM 写入的数据output reg        rd_en,            //SDRAM 读使能input      [15:0] rd_data,          //SDRAM 读出的数据input             sdram_init_done,  //SDRAM 初始化完成标志output reg        error_flag        //SDRAM 读写测试错误标志);//reg define
reg        init_done_d0;                //寄存SDRAM初始化完成信号
reg        init_done_d1;                //寄存SDRAM初始化完成信号
reg [10:0] wr_cnt;                      //写操作计数器
reg [10:0] rd_cnt;                      //读操作计数器
reg        rd_valid;                    //读数据有效标志//*****************************************************
//**                    main code
//***************************************************** //同步SDRAM初始化完成信号
always @(posedge clk_50m or negedge rst_n) beginif(!rst_n) begininit_done_d0 <= 1'b0;init_done_d1 <= 1'b0;endelse begininit_done_d0 <= sdram_init_done;init_done_d1 <= init_done_d0;end
end            //SDRAM初始化完成之后,写操作计数器开始计数
always @(posedge clk_50m or negedge rst_n) beginif(!rst_n) wr_cnt <= 11'd0;  else if(init_done_d1 && (wr_cnt <= 11'd1024))wr_cnt <= wr_cnt + 1'b1;elsewr_cnt <= wr_cnt;
end    //SDRAM写端口FIFO的写使能、写数据(1~1024)
always @(posedge clk_50m or negedge rst_n) beginif(!rst_n) begin      wr_en   <= 1'b0;wr_data <= 16'd0;endelse if(wr_cnt >= 11'd1 && (wr_cnt <= 11'd1024)) beginwr_en   <= 1'b1;            //写使能拉高wr_data <= wr_cnt;          //写入数据1~1024end    else beginwr_en   <= 1'b0;wr_data <= 16'd0;end
end        //写入数据完成后,开始读操作
always @(posedge clk_50m or negedge rst_n) beginif(!rst_n) rd_en <= 1'b0;else if(wr_cnt > 11'd1024)          //写数据完成rd_en <= 1'b1;                  //读使能拉高
end//对读操作计数
always @(posedge clk_50m or negedge rst_n) beginif(!rst_n) rd_cnt <= 11'd0;else if(rd_en) beginif(rd_cnt < 11'd1024)rd_cnt <= rd_cnt + 1'b1;elserd_cnt <= 11'd1;end
end//第一次读取的数据无效,后续读操作所读取的数据才有效
always @(posedge clk_50m or negedge rst_n) beginif(!rst_n) rd_valid <= 1'b0;else if(rd_cnt == 11'd1024)         //等待第一次读操作结束rd_valid <= 1'b1;               //后续读取的数据有效elserd_valid <= rd_valid;
end            //读数据有效时,若读取数据错误,给出标志信号
always @(posedge clk_50m or negedge rst_n) beginif(!rst_n)error_flag <= 1'b0; else if(rd_valid && (rd_data != rd_cnt))error_flag <= 1'b1;             //若读取的数据错误,将错误标志位拉高 elseerror_flag <= error_flag;
endendmodule 

SDRAM 控制器顶层模块:SDRAM top模块的目的将FIFO控制模块与SDRAM控制模块封装在一起,与用户模块和外部SDRAM交互。


 SDRAM 控制器顶层模块:


module  sdram_top(input         ref_clk,                  //sdram 控制器参考时钟input         out_clk,                  //用于输出的相位偏移时钟input         rst_n,                    //系统复位//用户写端口         input         wr_clk,                   //写端口FIFO: 写时钟input         wr_en,                    //写端口FIFO: 写使能input  [15:0] wr_data,                  //写端口FIFO: 写数据input  [23:0] wr_min_addr,              //写SDRAM的起始地址input  [23:0] wr_max_addr,              //写SDRAM的结束地址input  [ 9:0] wr_len,                   //写SDRAM时的数据突发长度input         wr_load,                  //写端口复位: 复位写地址,清空写FIFO//用户读端口input         rd_clk,                   //读端口FIFO: 读时钟input         rd_en,                    //读端口FIFO: 读使能output [15:0] rd_data,                  //读端口FIFO: 读数据input  [23:0] rd_min_addr,              //读SDRAM的起始地址input  [23:0] rd_max_addr,              //读SDRAM的结束地址input  [ 9:0] rd_len,                   //从SDRAM中读数据时的突发长度input         rd_load,                  //读端口复位: 复位读地址,清空读FIFO//用户控制端口  input         sdram_read_valid,         //SDRAM 读使能output        sdram_init_done,          //SDRAM 初始化完成标志//SDRAM 芯片接口output        sdram_clk,                //SDRAM 芯片时钟output        sdram_cke,                //SDRAM 时钟有效output        sdram_cs_n,               //SDRAM 片选output        sdram_ras_n,              //SDRAM 行有效output        sdram_cas_n,              //SDRAM 列有效output        sdram_we_n,               //SDRAM 写有效output [ 1:0] sdram_ba,                 //SDRAM Bank地址output [12:0] sdram_addr,               //SDRAM 行/列地址inout  [15:0] sdram_data,               //SDRAM 数据output [ 1:0] sdram_dqm                 //SDRAM 数据掩码);//wire define
wire        sdram_wr_req;                   //sdram 写请求
wire        sdram_wr_ack;                   //sdram 写响应
wire [23:0] sdram_wr_addr;                  //sdram 写地址
wire [15:0] sdram_din;                      //写入sdram中的数据wire        sdram_rd_req;                   //sdram 读请求
wire        sdram_rd_ack;                   //sdram 读响应
wire [23:0] sdram_rd_addr;                   //sdram 读地址
wire [15:0] sdram_dout;                     //从sdram中读出的数据//*****************************************************
//**                    main code
//*****************************************************
assign  sdram_clk = out_clk;                //将相位偏移时钟输出给sdram芯片
assign  sdram_dqm = 2'b00;                  //读写过程中均不屏蔽数据线//SDRAM 读写端口FIFO控制模块
sdram_fifo_ctrl u_sdram_fifo_ctrl(.clk_ref          (ref_clk),          //SDRAM控制器时钟.rst_n              (rst_n),            //系统复位//用户写端口.clk_write             (wr_clk),           //写端口FIFO: 写时钟.wrf_wrreq            (wr_en),            //写端口FIFO: 写请求.wrf_din          (wr_data),          //写端口FIFO: 写数据  .wr_min_addr        (wr_min_addr),      //写SDRAM的起始地址.wr_max_addr       (wr_max_addr),      //写SDRAM的结束地址.wr_length         (wr_len),           //写SDRAM时的数据突发长度.wr_load            (wr_load),          //写端口复位: 复位写地址,清空写FIFO    //用户读端口.clk_read          (rd_clk),           //读端口FIFO: 读时钟.rdf_rdreq            (rd_en),            //读端口FIFO: 读请求.rdf_dout         (rd_data),          //读端口FIFO: 读数据.rd_min_addr      (rd_min_addr),      //读SDRAM的起始地址.rd_max_addr       (rd_max_addr),      //读SDRAM的结束地址.rd_length         (rd_len),           //从SDRAM中读数据时的突发长度.rd_load          (rd_load),          //读端口复位: 复位读地址,清空读FIFO//用户控制端口  .sdram_read_valid   (sdram_read_valid), //sdram 读使能.sdram_init_done (sdram_init_done),  //sdram 初始化完成标志//SDRAM 控制器写端口.sdram_wr_req      (sdram_wr_req),     //sdram 写请求.sdram_wr_ack        (sdram_wr_ack),     //sdram 写响应.sdram_wr_addr       (sdram_wr_addr),    //sdram 写地址.sdram_din           (sdram_din),        //写入sdram中的数据//SDRAM 控制器读端口.sdram_rd_req        (sdram_rd_req),     //sdram 读请求.sdram_rd_ack        (sdram_rd_ack),     //sdram 读响应.sdram_rd_addr       (sdram_rd_addr),    //sdram 读地址.sdram_dout          (sdram_dout)        //从sdram中读出的数据);//SDRAM控制器
sdram_controller u_sdram_controller(.clk                (ref_clk),          //sdram 控制器时钟.rst_n             (rst_n),            //系统复位//SDRAM 控制器写端口    .sdram_wr_req       (sdram_wr_req),     //sdram 写请求.sdram_wr_ack        (sdram_wr_ack),     //sdram 写响应.sdram_wr_addr       (sdram_wr_addr),    //sdram 写地址.sdram_wr_burst      (wr_len),           //写sdram时数据突发长度.sdram_din       (sdram_din),        //写入sdram中的数据//SDRAM 控制器读端口.sdram_rd_req        (sdram_rd_req),     //sdram 读请求.sdram_rd_ack        (sdram_rd_ack),     //sdram 读响应.sdram_rd_addr       (sdram_rd_addr),    //sdram 读地址.sdram_rd_burst      (rd_len),           //读sdram时数据突发长度.sdram_dout          (sdram_dout),       //从sdram中读出的数据.sdram_init_done  (sdram_init_done),  //sdram 初始化完成标志//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_data            (sdram_data)        //SDRAM 数据  );endmodule 

SDRAM 控制器:完成与上层模块及SDRAM的状态控制模块,命令控制模块,数据模块的交互。


module sdram_controller(input         clk,              //SDRAM控制器时钟,100MHzinput         rst_n,          //系统复位信号,低电平有效//SDRAM 控制器写端口 input         sdram_wr_req,     //写SDRAM请求信号output        sdram_wr_ack,     //写SDRAM响应信号input  [23:0] sdram_wr_addr,    //SDRAM写操作的地址input  [ 9:0] sdram_wr_burst,   //写sdram时数据突发长度input  [15:0] sdram_din,        //写入SDRAM的数据//SDRAM 控制器读端口  input         sdram_rd_req,     //读SDRAM请求信号output        sdram_rd_ack,     //读SDRAM响应信号input  [23:0] sdram_rd_addr,    //SDRAM写操作的地址input  [ 9:0] sdram_rd_burst,   //读sdram时数据突发长度output [15:0] sdram_dout,       //从SDRAM读出的数据output       sdram_init_done,  //SDRAM 初始化完成标志// FPGA与SDRAM硬件接口output        sdram_cke,        // SDRAM 时钟有效信号output        sdram_cs_n,        // SDRAM 片选信号output        sdram_ras_n,     // SDRAM 行地址选通脉冲output        sdram_cas_n,      // SDRAM 列地址选通脉冲output        sdram_we_n,       // SDRAM 写允许位output [ 1:0] sdram_ba,            // SDRAM L-Bank地址线output [12:0] sdram_addr,     // SDRAM 地址总线inout  [15:0] sdram_data       // SDRAM 数据总线);//wire define
wire [4:0] init_state;              // SDRAM初始化状态
wire [3:0] work_state;              // SDRAM工作状态
wire [9:0] cnt_clk;                 // 延时计数器
wire       sdram_rd_wr;             // SDRAM读/写控制信号,低电平为写,高电平为读//*****************************************************
//**                    main code
//*****************************************************     // SDRAM 状态控制模块
sdram_ctrl u_sdram_ctrl(            .clk                (clk),                      .rst_n              (rst_n),.sdram_wr_req       (sdram_wr_req), .sdram_rd_req       (sdram_rd_req),.sdram_wr_ack       (sdram_wr_ack),.sdram_rd_ack       (sdram_rd_ack),                       .sdram_wr_burst     (sdram_wr_burst),.sdram_rd_burst     (sdram_rd_burst),.sdram_init_done    (sdram_init_done),.init_state         (init_state),.work_state         (work_state),.cnt_clk            (cnt_clk),.sdram_rd_wr        (sdram_rd_wr));// SDRAM 命令控制模块
sdram_cmd u_sdram_cmd(              .clk                (clk),.rst_n              (rst_n),.sys_wraddr         (sdram_wr_addr),          .sys_rdaddr         (sdram_rd_addr),.sdram_wr_burst     (sdram_wr_burst),.sdram_rd_burst     (sdram_rd_burst),.init_state         (init_state), .work_state         (work_state),.cnt_clk            (cnt_clk),.sdram_rd_wr        (sdram_rd_wr),.sdram_cke          (sdram_cke),       .sdram_cs_n         (sdram_cs_n),   .sdram_ras_n        (sdram_ras_n),  .sdram_cas_n        (sdram_cas_n),  .sdram_we_n         (sdram_we_n),   .sdram_ba           (sdram_ba),         .sdram_addr         (sdram_addr));// SDRAM 数据读写模块
sdram_data u_sdram_data(        .clk                (clk),.rst_n              (rst_n),.sdram_data_in      (sdram_din),.sdram_data_out     (sdram_dout),.work_state         (work_state),.cnt_clk            (cnt_clk),.sdram_data         (sdram_data));endmodule 

状态命令参数:


// SDRAM 初始化过程各个状态
`define        I_NOP           5'd0                           //等待上电200us稳定期结束
`define        I_PRE           5'd1                           //预充电状态
`define        I_TRP           5'd2                           //等待预充电完成         tRP
`define        I_AR            5'd3                           //自动刷新
`define        I_TRF           5'd4                           //等待自动刷新结束    tRC
`define        I_MRS           5'd5                           //模式寄存器设置
`define        I_TRSC          5'd6                           //等待模式寄存器设置完成 tRSC
`define        I_DONE          5'd7                           //初始化完成// SDRAM 工作过程各个状态
`define        W_IDLE          4'd0                            //空闲
`define        W_ACTIVE        4'd1                            //行有效
`define        W_TRCD          4'd2                            //行有效等待
`define        W_READ          4'd3                            //读操作
`define        W_CL            4'd4                            //潜伏期
`define        W_RD            4'd5                            //读数据
`define        W_WRITE         4'd6                            //写操作
`define        W_WD            4'd7                            //写数据
`define        W_TWR           4'd8                            //写回
`define        W_PRE           4'd9                            //预充电
`define        W_TRP           4'd10                           //预充电等待
`define        W_AR            4'd11                           //自动刷新
`define        W_TRFC          4'd12                           //自动刷新等待//延时参数
`define        end_trp         cnt_clk == TRP_CLK              //预充电有效周期结束
`define        end_trfc        cnt_clk == TRC_CLK              //自动刷新周期结束
`define        end_trsc        cnt_clk == TRSC_CLK             //模式寄存器设置时钟周期结束
`define        end_trcd        cnt_clk == TRCD_CLK-1           //行选通周期结束
`define     end_tcl            cnt_clk == TCL_CLK-1            //潜伏期结束
`define     end_rdburst        cnt_clk == sdram_rd_burst-4     //读突发终止
`define        end_tread       cnt_clk == sdram_rd_burst+2     //突发读结束
`define     end_wrburst        cnt_clk == sdram_wr_burst-1     //写突发终止
`define        end_twrite      cnt_clk == sdram_wr_burst-1     //突发写结束
`define        end_twr         cnt_clk == TWR_CLK                //写回周期结束//SDRAM控制信号命令
`define        CMD_INIT        5'b01111                       // INITIATE
`define        CMD_NOP         5'b10111                       // NOP COMMAND
`define        CMD_ACTIVE      5'b10011                       // ACTIVE COMMAND
`define        CMD_READ        5'b10101                       // READ COMMADN
`define        CMD_WRITE       5'b10100                       // WRITE COMMAND
`define        CMD_B_STOP      5'b10110                       // BURST STOP
`define        CMD_PRGE        5'b10010                       // PRECHARGE
`define        CMD_A_REF       5'b10001                       // AOTO REFRESH
`define        CMD_LMR         5'b10000                       // LODE MODE REGISTER

状态控制模块:初始化状态及工作状态和刷新计数器设置。

//*******
// Descriptions:        SDRAM 状态控制模块module sdram_ctrl(input            clk,             //系统时钟input            rst_n,               //复位信号,低电平有效input            sdram_wr_req,       //写SDRAM请求信号input            sdram_rd_req,      //读SDRAM请求信号output           sdram_wr_ack,      //写SDRAM响应信号output           sdram_rd_ack,      //读SDRAM响应信号input      [9:0] sdram_wr_burst,    //突发写SDRAM字节数(1-512个)input      [9:0] sdram_rd_burst, //突发读SDRAM字节数(1-256个) output           sdram_init_done,   //SDRAM系统初始化完毕信号output reg [4:0] init_state,        //SDRAM初始化状态output reg [3:0] work_state,        //SDRAM工作状态output reg [9:0] cnt_clk,            //时钟计数器output reg       sdram_rd_wr         //SDRAM读/写控制信号,低电平为写,高电平为读);`include "sdram_para.v"                    //包含SDRAM参数定义模块//parameter define
parameter  TRP_CLK    = 10'd4;            //预充电有效周期
parameter  TRC_CLK    = 10'd6;            //自动刷新周期
parameter  TRSC_CLK   = 10'd6;            //模式寄存器设置时钟周期
parameter  TRCD_CLK   = 10'd2;            //行选通周期
parameter  TCL_CLK    = 10'd3;            //列潜伏期
parameter  TWR_CLK    = 10'd2;            //写入校正//reg define
reg [14:0] cnt_200us;                   //SDRAM 上电稳定期200us计数器
reg [10:0] cnt_refresh;                 //刷新计数寄存器
reg        sdram_ref_req;               //SDRAM 自动刷新请求信号
reg        cnt_rst_n;                   //延时计数器复位信号,低有效
reg [ 3:0] init_ar_cnt;                 //初始化过程自动刷新计数器//wire define
wire       done_200us;                  //上电后200us输入稳定期结束标志位
wire       sdram_ref_ack;               //SDRAM自动刷新请求应答信号   //*****************************************************
//**                    main code
//***************************************************** //SDRAM上电后200us稳定期结束后,将标志信号拉高
assign done_200us = (cnt_200us == 15'd20_000);//SDRAM初始化完成标志
assign sdram_init_done = (init_state == `I_DONE);//SDRAM 自动刷新应答信号
assign sdram_ref_ack = (work_state == `W_AR);//写SDRAM响应信号
assign sdram_wr_ack = ((work_state == `W_TRCD) & ~sdram_rd_wr) | ( work_state == `W_WRITE)|((work_state == `W_WD) & (cnt_clk < sdram_wr_burst - 2'd2));//读SDRAM响应信号
assign sdram_rd_ack = (work_state == `W_RD) & (cnt_clk >= 10'd1) & (cnt_clk < sdram_rd_burst + 2'd1);//上电后计时200us,等待SDRAM状态稳定
always @ (posedge clk or negedge rst_n) beginif(!rst_n) cnt_200us <= 15'd0;else if(cnt_200us < 15'd20_000) cnt_200us <= cnt_200us + 1'b1;elsecnt_200us <= cnt_200us;
end//刷新计数器循环计数7812ns (60ms内完成全部8192行刷新操作)
always @ (posedge clk or negedge rst_n)if(!rst_n) cnt_refresh <= 11'd0;else if(cnt_refresh < 11'd781)      // 64ms/8192 =7812nscnt_refresh <= cnt_refresh + 1'b1;  else cnt_refresh <= 11'd0; //SDRAM 刷新请求
always @ (posedge clk or negedge rst_n)if(!rst_n) sdram_ref_req <= 1'b0;else if(cnt_refresh == 11'd780) sdram_ref_req <= 1'b1;            //刷新计数器计时达7812ns时产生刷新请求else if(sdram_ref_ack) sdram_ref_req <= 1'b0;           //收到刷新请求响应信号后取消刷新请求 //延时计数器对时钟计数
always @ (posedge clk or negedge rst_n) if(!rst_n) cnt_clk <= 10'd0;else if(!cnt_rst_n)                 //在cnt_rst_n为低电平时延时计数器清零cnt_clk <= 10'd0;else cnt_clk <= cnt_clk + 1'b1;//初始化过程中对自动刷新操作计数
always @ (posedge clk or negedge rst_n) if(!rst_n) init_ar_cnt <= 4'd0;else if(init_state == `I_NOP) init_ar_cnt <= 4'd0;else if(init_state == `I_AR)init_ar_cnt <= init_ar_cnt + 1'b1;elseinit_ar_cnt <= init_ar_cnt;//SDRAM的初始化状态机
always @ (posedge clk or negedge rst_n) beginif(!rst_n) init_state <= `I_NOP;else case (init_state)//上电复位后200us结束则进入下一状态`I_NOP:  init_state <= done_200us  ? `I_PRE : `I_NOP;//预充电状态`I_PRE:  init_state <= `I_TRP;//预充电等待,TRP_CLK个时钟周期`I_TRP:  init_state <= (`end_trp)  ? `I_AR  : `I_TRP;//自动刷新`I_AR :  init_state <= `I_TRF; //等待自动刷新结束,TRC_CLK个时钟周期`I_TRF:  init_state <= (`end_trfc) ? //连续8次自动刷新操作((init_ar_cnt == 4'd8) ? `I_MRS : `I_AR) : `I_TRF;//模式寄存器设置`I_MRS:  init_state <= `I_TRSC;    //等待模式寄存器设置完成,TRSC_CLK个时钟周期`I_TRSC: init_state <= (`end_trsc) ? `I_DONE : `I_TRSC;//SDRAM的初始化设置完成标志`I_DONE: init_state <= `I_DONE;default: init_state <= `I_NOP;endcase
end//SDRAM的工作状态机,工作包括读、写以及自动刷新操作
always @ (posedge clk or negedge rst_n) beginif(!rst_n) work_state <= `W_IDLE;          //空闲状态elsecase(work_state)//定时自动刷新请求,跳转到自动刷新状态`W_IDLE: if(sdram_ref_req & sdram_init_done) beginwork_state <= `W_AR;         sdram_rd_wr <= 1'b1;end                //写SDRAM请求,跳转到行有效状态else if(sdram_wr_req & sdram_init_done) beginwork_state <= `W_ACTIVE;sdram_rd_wr <= 1'b0;   end                //读SDRAM请求,跳转到行有效状态else if(sdram_rd_req && sdram_init_done) beginwork_state <= `W_ACTIVE;sdram_rd_wr <= 1'b1;   end                //无操作请求,保持空闲状态else begin work_state <= `W_IDLE;sdram_rd_wr <= 1'b1;end`W_ACTIVE:                  //行有效,跳转到行有效等待状态work_state <= `W_TRCD;`W_TRCD: if(`end_trcd)      //行有效等待结束,判断当前是读还是写if(sdram_rd_wr)//读:进入读操作状态work_state <= `W_READ;else           //写:进入写操作状态work_state <= `W_WRITE;else work_state <= `W_TRCD;`W_READ:                 //读操作,跳转到潜伏期work_state <= `W_CL;    `W_CL:                     //潜伏期:等待潜伏期结束,跳转到读数据状态work_state <= (`end_tcl) ? `W_RD:`W_CL;                                          `W_RD:                     //读数据:等待读数据结束,跳转到预充电状态work_state <= (`end_tread) ? `W_PRE:`W_RD;`W_WRITE:                 //写操作:跳转到写数据状态work_state <= `W_WD;`W_WD:                       //写数据:等待写数据结束,跳转到写回周期状态work_state <= (`end_twrite) ? `W_TWR:`W_WD;                         `W_TWR:                        //写回周期:写回周期结束,跳转到预充电状态work_state <= (`end_twr) ? `W_PRE:`W_TWR;`W_PRE:                        //预充电:跳转到预充电等待状态work_state <= `W_TRP;`W_TRP:                   //预充电等待:预充电等待结束,进入空闲状态work_state <= (`end_trp) ? `W_IDLE:`W_TRP;`W_AR:                        //自动刷新操作,跳转到自动刷新等待work_state <= `W_TRFC;             `W_TRFC:                  //自动刷新等待:自动刷新等待结束,进入空闲状态work_state <= (`end_trfc) ? `W_IDLE:`W_TRFC;default:    work_state <= `W_IDLE;endcase
end//计数器控制逻辑
always @ (*) begincase (init_state)`I_NOP:     cnt_rst_n <= 1'b0;     //延时计数器清零(cnt_rst_n低电平复位)`I_PRE:   cnt_rst_n <= 1'b1;     //预充电:延时计数器启动(cnt_rst_n高电平启动)//等待预充电延时计数结束后,清零计数器`I_TRP:     cnt_rst_n <= (`end_trp) ? 1'b0 : 1'b1;//自动刷新:延时计数器启动`I_AR:cnt_rst_n <= 1'b1;//等待自动刷新延时计数结束后,清零计数器`I_TRF:cnt_rst_n <= (`end_trfc) ? 1'b0 : 1'b1; `I_MRS:  cnt_rst_n <= 1'b1;       //模式寄存器设置:延时计数器启动//等待模式寄存器设置延时计数结束后,清零计数器`I_TRSC: cnt_rst_n <= (`end_trsc) ? 1'b0:1'b1;`I_DONE: begin                  //初始化完成后,判断工作状态case (work_state)`W_IDLE: cnt_rst_n <= 1'b0;//行有效:延时计数器启动`W_ACTIVE:  cnt_rst_n <= 1'b1;//行有效延时计数结束后,清零计数器`W_TRCD:   cnt_rst_n <= (`end_trcd)   ? 1'b0 : 1'b1;//潜伏期延时计数结束后,清零计数器`W_CL:        cnt_rst_n <= (`end_tcl)    ? 1'b0 : 1'b1;//读数据延时计数结束后,清零计数器`W_RD:        cnt_rst_n <= (`end_tread)  ? 1'b0 : 1'b1;//写数据延时计数结束后,清零计数器`W_WD:        cnt_rst_n <= (`end_twrite) ? 1'b0 : 1'b1;//写回周期延时计数结束后,清零计数器`W_TWR:      cnt_rst_n <= (`end_twr)    ? 1'b0 : 1'b1;//预充电等待延时计数结束后,清零计数器`W_TRP: cnt_rst_n <= (`end_trp) ? 1'b0 : 1'b1;//自动刷新等待延时计数结束后,清零计数器`W_TRFC:  cnt_rst_n <= (`end_trfc)   ? 1'b0 : 1'b1;default:    cnt_rst_n <= 1'b0;endcaseenddefault: cnt_rst_n <= 1'b0;endcase
endendmodule 

SDRAM数据读写模块:根据输入的读写数据及控制读写信号,写数据进入SDRAM,读数据进寄存器,传入上层模块。


module sdram_data(input             clk,                //系统时钟input             rst_n,          //低电平复位信号input   [15:0]    sdram_data_in,    //写入SDRAM中的数据output  [15:0]    sdram_data_out,   //从SDRAM中读取的数据input   [ 3:0]    work_state,       //SDRAM工作状态寄存器input   [ 9:0]    cnt_clk,            //时钟计数inout   [15:0]    sdram_data      //SDRAM数据总线);`include "sdram_para.v"                 //包含SDRAM参数定义模块//reg define
reg        sdram_out_en;                //SDRAM数据总线输出使能
reg [15:0] sdram_din_r;                 //寄存写入SDRAM中的数据
reg [15:0] sdram_dout_r;                //寄存从SDRAM中读取的数据//*****************************************************
//**                    main code
//***************************************************** //SDRAM 双向数据线作为输入时保持高阻态
assign sdram_data = sdram_out_en ? sdram_din_r : 16'hzzzz;//输出SDRAM中读取的数据
assign sdram_data_out = sdram_dout_r;//SDRAM 数据总线输出使能
always @ (posedge clk or negedge rst_n) begin if(!rst_n) sdram_out_en <= 1'b0;else if((work_state == `W_WRITE) | (work_state == `W_WD)) sdram_out_en <= 1'b1;            //向SDRAM中写数据时,输出使能拉高else sdram_out_en <= 1'b0;
end//将待写入数据送到SDRAM数据总线上
always @ (posedge clk or negedge rst_n) beginif(!rst_n) sdram_din_r <= 16'd0;else if((work_state == `W_WRITE) | (work_state == `W_WD))sdram_din_r <= sdram_data_in; //寄存写入SDRAM中的数据
end//读数据时,寄存SDRAM数据线上的数据
always @ (posedge clk or negedge rst_n) beginif(!rst_n) sdram_dout_r <= 16'd0;else if(work_state == `W_RD) sdram_dout_r <= sdram_data;     //寄存从SDRAM中读取的数据
endendmodule 

SDRAM命令控制模块:通过不同的状态,向SDRAM芯片输入不同的命令数据。


module sdram_cmd(input             clk,             //系统时钟input             rst_n,          //低电平复位信号input      [23:0] sys_wraddr,      //写SDRAM时地址input      [23:0] sys_rdaddr,        //读SDRAM时地址input      [ 9:0] sdram_wr_burst,    //突发写SDRAM字节数input      [ 9:0] sdram_rd_burst,  //突发读SDRAM字节数input      [ 4:0] init_state,      //SDRAM初始化状态input      [ 3:0] work_state,       //SDRAM工作状态input      [ 9:0] cnt_clk,           //延时计数器 input             sdram_rd_wr,      //SDRAM读/写控制信号,低电平为写output            sdram_cke,     //SDRAM时钟有效信号output            sdram_cs_n,      //SDRAM片选信号output            sdram_ras_n,       //SDRAM行地址选通脉冲output            sdram_cas_n,        //SDRAM列地址选通脉冲output            sdram_we_n,     //SDRAM写允许位output reg [ 1:0] sdram_ba,          //SDRAM的L-Bank地址线output reg [12:0] sdram_addr       //SDRAM地址总线);`include "sdram_para.v"                 //包含SDRAM参数定义模块//reg define
reg  [ 4:0] sdram_cmd_r;                //SDRAM操作指令//wire define
wire [23:0] sys_addr;                   //SDRAM读写地址 //*****************************************************
//**                    main code
//***************************************************** //SDRAM 控制信号线赋值
assign {sdram_cke,sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} = sdram_cmd_r;//SDRAM 读/写地址总线控制
assign sys_addr = sdram_rd_wr ? sys_rdaddr : sys_wraddr;//SDRAM 操作指令控制
always @ (posedge clk or negedge rst_n) beginif(!rst_n) beginsdram_cmd_r <= `CMD_INIT;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;endelsecase(init_state)//初始化过程中,以下状态不执行任何指令`I_NOP,`I_TRP,`I_TRF,`I_TRSC: beginsdram_cmd_r <= `CMD_NOP;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;   end`I_PRE: begin               //预充电指令sdram_cmd_r <= `CMD_PRGE;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;end `I_AR: begin//自动刷新指令sdram_cmd_r <= `CMD_A_REF;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;                     end                 `I_MRS: begin              //模式寄存器设置指令sdram_cmd_r <= `CMD_LMR;sdram_ba    <= 2'b00;sdram_addr  <= {    //利用地址线设置模式寄存器,可根据实际需要进行修改3'b000,            //预留1'b0,          //读写方式 A9=0,突发读&突发写2'b00,          //默认,{A8,A7}=003'b011,         //CAS潜伏期设置,这里设置为3,{A6,A5,A4}=0111'b0,           //突发传输方式,这里设置为顺序,A3=03'b111         //突发长度,这里设置为页突发,{A2,A1,A0}=011};end  `I_DONE:                    //SDRAM初始化完成case(work_state)    //以下工作状态不执行任何指令`W_IDLE,`W_TRCD,`W_CL,`W_TWR,`W_TRP,`W_TRFC: beginsdram_cmd_r <= `CMD_NOP;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;end`W_ACTIVE: begin//行有效指令sdram_cmd_r <= `CMD_ACTIVE;sdram_ba    <= sys_addr[23:22];sdram_addr  <= sys_addr[21:9];end`W_READ: begin  //读操作指令sdram_cmd_r <= `CMD_READ;sdram_ba    <= sys_addr[23:22];sdram_addr  <= {4'b0000,sys_addr[8:0]};end`W_RD: begin    //突发传输终止指令if(`end_rdburst) sdram_cmd_r <= `CMD_B_STOP;else beginsdram_cmd_r <= `CMD_NOP;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;endend                                `W_WRITE: begin //写操作指令sdram_cmd_r <= `CMD_WRITE;sdram_ba    <= sys_addr[23:22];sdram_addr  <= {4'b0000,sys_addr[8:0]};end       `W_WD: begin    //突发传输终止指令if(`end_wrburst) sdram_cmd_r <= `CMD_B_STOP;else beginsdram_cmd_r <= `CMD_NOP;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;endend`W_PRE:begin    //预充电指令sdram_cmd_r <= `CMD_PRGE;sdram_ba    <= sys_addr[23:22];sdram_addr  <= 13'h0000;end              `W_AR: begin    //自动刷新指令sdram_cmd_r <= `CMD_A_REF;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;enddefault: beginsdram_cmd_r <= `CMD_NOP;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;endendcasedefault: beginsdram_cmd_r <= `CMD_NOP;sdram_ba    <= 2'b11;sdram_addr  <= 13'h1fff;endendcase
endendmodule 

fifo读写控制模块:通过两个fifo读写ip核完成与sdram控制模块的交互,及与用户控制的交互

//fifo读写控制模块/*该fifo控制模块下游读写两个fifo,且两个fifo分别连接yoghurt模块和SDRAM模块,要分别设置接口,对fifo来说需要有时钟、数据、请求应答信号,来完成缓冲任务,加上复位、当前容量寄存器*/
module sdram_fifo_ctrl(input            clk_ref;        //参考时钟input             sys_rst;//用户写端口 input           clk_write;      //用户写时钟50minput             wr_req;         //写请求input [15:0]       wr_data;input [23:0]        wr_min_addr;input [23:0]        wr_max_addr;input [9:0]     wr_brust_len;input          wr_load_flag;//用户读端口    input           clk_read;       //用户读时钟50minput             rd_req;         //读请求input [15:0]       rd_data;        //读数据input [23:0]       rd_min_addr;input [23:0]        rd_max_addr;input [9:0]     rd_brust_len;       //读突发长度input            rd_load_flag;//用户控制端口   input           sdram_init_done;    //初始化标志信号input          sdram_read_valid;   //读使能//sdram端口定义    output          sdram_wr_req;input          sdram_wr_ack;output [15:0]      sdram_wr_data;output reg [23:0] sdram_wr_addr;//sdram端口定义   output  reg     sdram_rd_req;input          sdram_rd_ack;input     [15:0]   sdram_rd_data;output reg [23:0] sdram_rd_addr);//寄存信号,用于捕获边沿触发reg           wr_req_1;               //写响应寄存器reg         wr_req_2;reg            rd_req_1;           reg         rd_req_2;   reg         sdram_read_valid_1;         //读有效寄存器reg         sdram_read_valid_2;reg          wr_load_flag_1;             // //写端口复位寄存器reg            wr_load_flag_2;reg          rd_load_flag_1;reg          rd_load_flag_2;wire     wr_done_flag;           //写操作结束下降沿wire      rd_done_flag;wire       wr_load_flag;           //写复位上升沿wire        rd_load_flag;wire [9:0]     wrf_use;                    //写端口FIFO中的数据量wire [9:0]    rdf_use;                    //读端口FIFO中的数据量//                    main  code//数据结束下降沿检测assign wr_done_flag = wr_req_1 & (~wr_req_2); //不发出请求信号
assign  rd_done_flag = rd_req_1 & (~rd_req_2);//复位上升沿检测assign  wr_load_flag = (~wr_load_flag_1) & wr_load_flag_2;
assign  rd_load_flag = (~rd_load_flag_1) & rd_load_flag_2;//写响应寄存器
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginwr_req_1 <= 1'b0;wr_req_2 <= 1'b0;endelse beginwr_req_1 <= wr_req;wr_req_2 <= wr_req_1;end
end//读响应器
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginrd_req_1 <= 1'b0;rd_req_2 <= 1'b0;endelse beginrd_req_1 <= rd_req;rd_req_2 <= rd_req_1;end
end//同步写端口复位信号,用于捕获wr_load上升沿
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginwr_load_flag_1 <= 1'b0; wr_load_flag_2 <= 1'b0;endelse beginwr_load_flag_1 <= wr_load_flag; wr_load_flag_2 <= wr_load_flag_1;end
end//同步读端口复位信号,用于捕获wr_load上升沿
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginrd_load_flag_1 <= 1'b0; rd_load_flag_2 <= 1'b0;endelse beginrd_load_flag_1 <= rd_load_flag; rd_load_flag_2 <= rd_load_flag_1;end
end//同步sdram读使能信号
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginsdram_read_valid_1 <= 1'b0; sdram_read_valid_2 <= 1'b0;endelse beginsdram_read_valid_1 <= sdram_read_valid;    sdram_read_valid_2 <= sdram_read_valid_1;end
end//sdram写地址产生模块
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginsdram_wr_addr <= 24'd0;endelse if(wr_load_flag)             //写复位sdram_wr_addr <= wr_min_addr;else if(wr_done_flag)     //当一次写数据传输结束begin        //若当前地址未到达最大则写地址累加if(sdram_wr_addr < wr_max_addr - wr_brust_len)   sdram_wr_addr <= sdram_rd_addr + wr_brust_len;elsesdram_wr_addr <= wr_min_addr;//若到达最大则回到最小地址end
end//sdram读地址产生模块
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginsdram_rd_addr <= 24'd0;endelse if(rd_load_flag)                  //读复位sdram_rd_addr <=rd_min_addr;else if(rd_done_flag)                  //当一次读数据传输结束begin         //若当前地址未到达最大地址,则读地址累加if(sdram_rd_addr < rd_max_addr - rd_brust_len)  sdram_rd_addr <= sdram_rd_addr + rd_brust_len;elsesdram_rd_addr <= rd_min_addr;  //若到达最大地址,则回到最小地址end
end//读写请求产生模块
always @(posedge clk_ref or negedge sys_rst)beginif(!sys_rst)beginsdram_wr_req <= 1'b0;           //对同一SDRAM通信,不可同时为1sdram_rd_req <= 1'b0;endelse if(sdram_init_done)begin            //初始化完成,才可发送请求信号if(wrf_use > wr_brust_len)begin   //当写fifo大于一个突发长度,可写入到sdram中sdram_wr_req <= 1'b1;sdram_rd_req <= 1'b0;end                     //当读fifo中数据小于一个突发长度,可从SDRAM中读出数据else if((rdf_use < rd_brust_len) && sdram_read_valid_2)beginsdram_wr_req <= 1'b0;sdram_rd_req <= 1'b1;endelsesdram_wr_req <= 1'b0;sdram_rd_req <= 1'b0;endelse beginsdram_wr_req <= 1'b0;sdram_rd_req <= 1'b0;end
end//例化写fifo ip核
wrfifo u_wrfifo(
//用户接口.wrclk        (clk_write),.wrreq      (wrf_wrreq),  //请求来自用户输入模块.data     (wr_data),//sdram接口.rdclk       (clk_ref),.rdreq        (sdram_wr_ack),  //满足写条件发出写请求,接收SDRAM的写应答.q          (sdram_wr_data),.wrusedw    (wrf_use),.aclr     (sys_rst | wr_load_flag)
);//例化读端口FIFO
rdfifo  u_rdfifo(//sdram接口.wrclk        (clk_ref),               //写时钟.wrreq        (sdram_rd_ack),          //写请求.data     (sdram_rd_data),             //写数据//用户接口.rdclk      (clk_read),              //读时钟.rdreq        (rd_req),            //读请求.q            (rd_data),               //读数据.wrusedw  (rdf_use),               //FIFO中的数据量.aclr       (~sys_rst | rd_load_flag)  //异步清零信号   );endmodule

FPGA学习日记(八)SDRAM的读写测试相关推荐

  1. 利用FPGA实现简单的sdram的读写操作

    没有什么事都是一帆风顺的,学业...让人学会了很多但是又让人难以忘怀...人生路上起起伏伏,并不是真心的付出就可以得到相同的回报,有时候可能还会恰恰相反... 好了,负面情绪就不带给大家了,博主还是来 ...

  2. FPGA学习笔记(八):ASK调制解调的仿真

    笔记八是ASK调制解调的仿真实现. ASK调制解调的实现原理:首先使用MATLAB产生存储基带波形的coe文件,再让ROM读取coe文件输出基带波形,然后DDS产生正弦波信号作为载波信号,接下来使用乘 ...

  3. FPGA学习之实现SDRAM

    1 废话篇 1.1 存储器 RAM 掉电数据会丢失 ROM不会丢失 但是读写速度比较慢 Flash 闪存 掉电数据不会丢失 容量小 读写速度比较快 SDRAM 优点:空间存储量大.读写速度快.价格相对 ...

  4. Node.js Up and Runing 学习日记(八)

    目录 连接池 基于 一个简单的Socker.io服务器 连接池 生产环境通常由多种资源组成: web服务器,缓存服务器和数据库服务器. 数据库服务器通常部署在web服务器之外的独立机器上,这使得面向公 ...

  5. FPGA学习日记(七)HDMI图像数据传输

    一.实现目标 将像素数据通过HDMI传输,在显示器上显示. 二.数据流传输 HDMI常采用TMDS传输(上升沿复位)方式: (1)通过三个通道分别可传入8位的rgb视频信号,2位的控制信号,4位的音频 ...

  6. JavaScript函数的学习一(学习日记八)

    一.函数的声明 - 函数:把一堆重复性的代码封装,哪里需要,那里调用 - JavaScript 有三种声明函数的方法. (1)function 命令   function命令声明的代码区块,就是一个函 ...

  7. FPGA学习日记(九)ZYNQ的GPIO—MIO接口控制

    一.GPIO简介 在ZYNQ中,PS端的引脚资源ZYNQ PS 中的外设可以通过 MIO( 54pin,Multiuse I/O,多用输入/输出)模块连接到 PS 端的引脚上,也可以通过 EMIO 连 ...

  8. FPGA学习日记(18)--数码管动态显示

    数据生成模块 module data_gen #(parameter CNT_MAX = 23'd4999_999 ,parameter DATA_MAX = 20'd999_999 ) ( inpu ...

  9. Python学习日记(八) 函数

    函数的结构: 函数的返回值: 1.当函数执行时运到return关键字将不再往下执行 def func():print("hello world!")print("hell ...

最新文章

  1. 据我所知,这是第一个完整实现运动分割、动态目标追踪等的「开源」动态SLAM系统!...
  2. 【WebRTC---入门篇】(一)WebRTC整体架构
  3. 整合营销推广该如何做?
  4. Mybatis与Ibatis比较(转载)
  5. mysql atlas路由_MySQL中间件 Atlas-1.0.3 安装记录
  6. CV学习笔记-数字图像概述
  7. “蓝脑”计划:人造大脑的可能性 文化·探索 CCTV_com
  8. 如何在外网访问家里电脑上的文件?
  9. slic codec
  10. 杰理之ANC降噪基本原理【篇】
  11. 百兆网络变压器原理图及网络变压器功能(附PDF工程图纸)
  12. 电商项目 的业务逻辑与相关要点
  13. 联通4g 小米不显示无服务器,小米旗舰机断流严重,信号满格消息却发不出去?...
  14. 薇娅,李佳琦都点赞的淘宝双11直播系统,是如何打造的?
  15. 【揭密:刘强东9年密谋的商业布局—京东快物流背后的核心技术盘点】
  16. 说说CAP 理论是什么?
  17. 三天快速制作易语言防破解网络验证注册码系统
  18. 灰帽python之旅_灰帽 Python之旅10
  19. 论手持设备应用的WebApp化!
  20. byte数据类,list数据类

热门文章

  1. Wechaty 李卓桓:我想要某种功能,你没有?那我来一个
  2. 国际金融统计 (IFS) 数据库1978-2020
  3. 深度学习与计算机视觉(12)_tensorflow实现基于深度学习的图像补全
  4. 开发一个商城需要多少钱 做一个电商网站大概多少钱
  5. WPF加载SVG格式的图片
  6. 大数据面试常见问题(三)——Hadoop部分
  7. php保存word没背景图,为什么word文档明明保存了却不见了
  8. 计算机音乐设备简单配置,计算机音乐与作曲基础(高等学校艺术类专业计算机规划教材)...
  9. 不叫 Andromeda?Google 新系统疑为 Fuchsia
  10. C# CSharp计算标准偏差 重复精度 和Excel中的STDEV函数相同