大家好,又见面了,我是你们的朋友全栈君。
同步动态随机存取内存(synchronous dynamic random-access memory,简称SDRAM)是有一个同步接口的动态随机存取内存(DRAM)。SDRAM的特点是需要定期进行刷新操作,这也要求SDRAM需要一个控制器来对SDRAM进行控制,更为详细的SDRAM的知识可以上网进行查找,这里不再做过多的阐述。
SDRAM在上电之后要进行初始化操作,初始化操作包括无操作稳定延时一段时间(常见为延时200us),然后所有bank都要预充电,之后进行两次刷新操作,最后对寄存器赋值(控制操作模式、CAS潜伏期、burst突发长度,突发传输方式等)。
初始化结束之后,SDRAM就可以进行正常的读写操作,不过需要注意,SDRAM要定时刷新,因为SDRAM是使用电容存储数据,但是电容会漏电(无法避免),因此需要刷新。
下面给出我设计的SDRAM控制器的有限状态机图(画的比较仓促,可能会出现漏洞,欢迎询问)
接下来我给出设计的verilog程序的结构图
结构图顶层信号在程序中可以见到;为了可以更好的测试SDRAM控制器,所以特地编写了一个master,用于接受或发送数据。
master的顶层信号为:
input clk,
input rst_n,
input idle_sdram,//高位表示sdram正处在空闲状态,可以接收发数据
input req_send,//用于测试,提醒master开始发送数据
input addr_ready,//告诉master更新地址
input flag_dq_wr,//在写操作时,告诉master何时更新数据
input [15:0] dq_rd,//读操作接收读到的地址
output reg con_tran,//用于连续发送,当master处于连续发送时,就一直保持高位,当地址已经完全发送出去时,等到master更新地址时,拉低该位,表示数据传输完成(完成传输数据时,master地址需要跳到默认地址去)
output reg [24:0] addr_out,//给控制器输出的地址,最高位表示读或者写,2位bank地址位,13位行地址位,9位列地址位
output reg req_wr_rd,//向控制器发出的读写请求
output reg [15:0] dq_wr//写数据
SDRAM控制器的顶层信号为:
input clk,
input rst_n,
input con_tran,//为高表示master连续发送,默认为低位。
input [24:0] addr_in,//最高位表示读或者写,高表示为写,低位表示为读,然后依次为bank地址,行地址,列地址
input req_wr_rd,//master第一次传输数据时,将其拉高,与地址同时发出,有效位为单个周期
input [15:0] dq_wr,
output wire [1:0] sdram_dqm,
output wire sdram_clk,
output wire sdram_cke,
output wire sdram_cs_n,
output wire sdram_ras_n,
output wire sdram_cas_n,
output wire sdram_we_n,
output reg [12:0] sdram_addr,
output reg [1:0] sdram_bank_addr,
inout wire [15:0] sdram_dq_in,
output wire [15:0] dq_rd,
output wire addr_ready, //为高时,告诉master更新行列地址
output wire flag_dq_wr,
//output wire idle_sdram,//告诉master sdram是否处于空闲状态
output reg req_send//插入的测试点,提示master开始发送信号
SDRAM控制器中读写模块比较复杂,其他模块很简单。该控制器设置burst长度为4,进入读写状态最开始进行行激活,之后若读写地址都在该行,那么可以连续的读写,不需要再行激活,并且连续读写之间没有空闲周期;若前后行地址不一致,则在预充电后,由读写状态直接进入IDLE状态,然后再次进入读写状态;每次进入和离开读写状态只进行一次行激活和预充电;可以保证由读转到写时,完全读出数据之后才进行写操作,同样中间不会有多有空闲周期。
下面给出一种情况下,读写模块里面部分信号的时序图
给出Modelsim仿真的一部分情况
开始
连续读写时遇到刷新
换行
最后给出代码
读写模块
1 module sdram_rd_wr( 2 input clk, 3 input rst_n, 4 input aref_req, 5 input wr_rd_en, 6 input con_tran, 7 input [24:0] addr_in, 8 output reg [3:0] cmd_reg, 9 output reg [12:0] sdram_addr, 10 output reg [1:0] sdram_bank_addr, 11 output reg flag_dq_wr, 12 output wire addr_ready, 13 output reg end_wr_rd, 14 output reg flag_aref_req 15 ); 16 17 //1+2+13+9 18 19 reg [24:0] addr_in_reg; 20 21 22 23 24 reg row_act; 25 26 localparam ROWACT =4'b0011; 27 localparam NOP =4'b0111; 28 localparam WR =4'b0100; 29 localparam RD =4'b0101; 30 localparam PRE =4'b0010; 31 32 wire flag_wr_rd; 33 reg flag_wr_rd_a; 34 reg flag_rd2wr; 35 36 reg [1:0] cnt_cmd; 37 38 39 40 reg end_en; 41 42 reg pre_en; 43 44 assign addr_ready=((cnt_cmd==2'd1)&&(con_tran==1'b1))? 1'b1:1'b0; 45 always@(posedge clk, negedge rst_n) 46 if(!rst_n) 47 addr_in_reg<=25'd0; 48 else if(wr_rd_en==1'b1||((end_en==1'b0)&&(cnt_cmd==2'd3))) 49 addr_in_reg<=addr_in; 50 else 51 addr_in_reg<=addr_in_reg; 52 53 always@(posedge clk, negedge rst_n) 54 if(!rst_n) 55 flag_dq_wr<=1'b0; 56 else if((flag_wr_rd==1'b1)&&(cnt_cmd==2'd0)&&(addr_in_reg[24]==1'b1)) 57 flag_dq_wr<=1'b1; 58 else if((flag_wr_rd==1'b1)&&(cnt_cmd==2'd0)&&(addr_in_reg[24]==1'b0)) 59 flag_dq_wr<=1'b0; 60 else if(pre_en==1'b1) 61 flag_dq_wr<=1'b0; 62 else 63 flag_dq_wr<=flag_dq_wr; 64 65 66 always@(posedge clk, negedge rst_n) 67 if(!rst_n) 68 row_act<=1'b0; 69 else 70 row_act<=wr_rd_en; 71 72 always@(posedge clk, negedge rst_n) 73 if(!rst_n) 74 cmd_reg<=NOP; 75 else if(row_act) 76 cmd_reg<=ROWACT; 77 else if(flag_wr_rd==1'b1&&cnt_cmd==2'd0) begin 78 if(addr_in_reg[24]==1'b1) 79 cmd_reg<=WR; 80 else 81 cmd_reg<=RD; 82 end 83 else if(pre_en) 84 cmd_reg<=PRE; 85 else 86 cmd_reg<=NOP; 87 88 89 always@(*) begin 90 case(cmd_reg) 91 ROWACT: begin 92 sdram_addr <=addr_in_reg[21:9]; 93 sdram_bank_addr <=addr_in_reg[22:21]; 94 end 95 96 WR: begin 97 sdram_addr <={3'b000,addr_in_reg[8:0]}; 98 sdram_bank_addr <=addr_in_reg[23:22]; 99 end 100 RD: begin 101 sdram_addr <={3'b000,addr_in_reg[8:0]}; 102 sdram_bank_addr <=addr_in_reg[23:22]; 103 end 104 PRE: begin 105 sdram_addr <=13'b0_0100_0000_0000; 106 sdram_bank_addr <=2'd0; 107 end 108 NOP: begin 109 sdram_addr <=13'd0; 110 sdram_bank_addr <=2'd0; 111 end 112 default: begin 113 sdram_addr <=13'd0; 114 sdram_bank_addr <=2'd0; 115 end 116 endcase 117 end 118 119 120 always@(posedge clk, negedge rst_n) 121 if(!rst_n) 122 flag_aref_req<=1'b0; 123 else if(aref_req) 124 flag_aref_req<=1'b1; 125 else if(wr_rd_en) 126 flag_aref_req<=1'b0; 127 else 128 flag_aref_req<=flag_aref_req; 129 130 always@(posedge clk, negedge rst_n) 131 if(!rst_n) 132 flag_wr_rd_a<=1'b0; 133 else if(cmd_reg==ROWACT) 134 flag_wr_rd_a<=1'b1; 135 else if(end_en==1'b1) 136 flag_wr_rd_a<=1'b0; 137 else 138 flag_wr_rd_a<=flag_wr_rd_a; 139 140 always@(posedge clk, negedge rst_n) 141 if(!rst_n) 142 flag_rd2wr<=1'b1; 143 else if(cnt_cmd==2'd3&&addr_in[24]==1'b0&&addr_in_reg[24]==1'b1&&!end_en) 144 flag_rd2wr<=1'b0; 145 else 146 flag_rd2wr<=1'b1; 147 148 assign flag_wr_rd=flag_rd2wr&flag_wr_rd_a; 149 150 always@(posedge clk, negedge rst_n) 151 if(!rst_n) 152 cnt_cmd<=2'd0; 153 else if(flag_wr_rd==1'b1) begin 154 if(cnt_cmd==2'd3) 155 cnt_cmd<=2'd0; 156 else 157 cnt_cmd<=cnt_cmd+1'b1; 158 end 159 else 160 cnt_cmd<=2'd0; 161 162 always@(posedge clk, negedge rst_n) 163 if(!rst_n) 164 end_en<=1'b0; 165 else if(cnt_cmd==2'd2) begin 166 if(con_tran==1'b0) 167 end_en<=1'b1; 168 else if(con_tran==1'b1&&flag_aref_req==1'b1) 169 end_en<=1'b1; 170 else if((con_tran==1'b1)&& !(addr_in[21:9]==addr_in_reg[21:9])) 171 end_en<=1'b1; 172 else 173 end_en<=1'b0; 174 end 175 else 176 end_en<=1'b0; 177 178 always@(posedge clk, negedge rst_n) 179 if(!rst_n) 180 pre_en<=1'b0; 181 else if(end_en) 182 pre_en<=1'b1; 183 else 184 pre_en<=1'b0; 185 186 187 always@(posedge clk,negedge rst_n) 188 if(!rst_n) 189 end_wr_rd<=1'b0; 190 else if(pre_en) 191 end_wr_rd<=1'b1; 192 else 193 end_wr_rd<=1'b0; 194 195 endmodule
初始化模块
1 module sdram_init( 2 input clk, 3 input rst_n, 4 output wire [12:0] init_addr, 5 output wire [1:0] bank_addr, 6 output reg [3:0] cmd_reg, 7 output reg end_init, 8 output reg flag_init 9 ); 10 11 12 reg flag_delay; 13 14 15 reg [13:0] cnt_delay; 16 localparam DELAY=14'd10000; 17 18 19 reg end_delay; 20 21 22 reg [3:0] cnt_init; 23 24 25 localparam INIT_NOP =4'b0111; 26 localparam INIT_PRE =4'b0010; 27 localparam INIT_ARF =4'b0001; 28 localparam INIT_MODSET=4'b0000; 29 30 31 always@(posedge clk, negedge rst_n) 32 if(!rst_n) 33 flag_delay<=1'b1; 34 else if(cnt_delay==DELAY) 35 flag_delay<=1'b0; 36 else 37 flag_delay<=flag_delay; 38 39 40 41 42 always@(posedge clk, negedge rst_n) 43 if(!rst_n) 44 cnt_delay<=14'd0; 45 else if(flag_delay==1'b1) 46 cnt_delay<=cnt_delay+1'b1; 47 else 48 cnt_delay<=14'd0; 49 50 51 52 always@(posedge clk, negedge rst_n) 53 if(!rst_n) 54 end_delay<=1'b1; 55 else if(cnt_delay==DELAY) 56 end_delay<=1'b1; 57 else 58 end_delay<=1'b0; 59 60 61 always@(posedge clk,negedge rst_n) 62 if(!rst_n) 63 cnt_init<=4'd0; 64 else if( flag_delay==1'b0 && flag_init==1'b1) 65 cnt_init<=cnt_init+1'b1; 66 else if(cnt_init==4'd12) 67 cnt_init<=4'd0; 68 else 69 cnt_init<=cnt_init; 70 71 72 73 always@(posedge clk, negedge rst_n) 74 if(!rst_n) 75 flag_init<=1'b1; 76 else if(end_init==1'b1) 77 flag_init<=1'b0; 78 else 79 flag_init<=flag_init; 80 81 82 always@(posedge clk, negedge rst_n) 83 if(!rst_n) 84 end_init<=1'b0; 85 else if(cnt_init==4'd12) 86 end_init<=1'b1; 87 else 88 end_init<=1'b0; 89 90 91 92 93 94 95 96 97 always@(posedge clk, negedge rst_n) 98 if(!rst_n) 99 cmd_reg<=INIT_NOP; 100 else if((flag_delay==1'b0) && (flag_init==1'b1)) 101 case(cnt_init) 102 4'd1: cmd_reg<=INIT_PRE; 103 4'd3: cmd_reg<=INIT_ARF; 104 4'd7: cmd_reg<=INIT_ARF; 105 4'd11:cmd_reg<=INIT_MODSET; 106 default: cmd_reg<=INIT_NOP; 107 endcase 108 else 109 cmd_reg<=INIT_NOP; 110 111 112 113 114 115 assign {bank_addr[1:0],init_addr[12:0]}=(cmd_reg==INIT_MODSET)? 15'b000_0000_0011_0010:15'b000_0100_0000_0000; 116 117 118 119 endmodule
刷新计数器
module aref_cunter( input clk, input rst_n, input end_init, output wire aref_req ); reg [8:0] aref_cnt; reg flag_aref; localparam AREF_DELAY=9'd380; always@(posedge clk, negedge rst_n) if(!rst_n) flag_aref<=1'b0; else if(end_init==1'b1) flag_aref<=1'b1; else flag_aref<=flag_aref; always@(posedge clk, negedge rst_n) if(!rst_n) aref_cnt<=9'd0; else if (flag_aref==1'b1) begin if(aref_cnt==AREF_DELAY) aref_cnt<=9'd0; else aref_cnt<=aref_cnt+1'b1; end else aref_cnt<=9'd0; assign aref_req=(aref_cnt==AREF_DELAY) ? 1'b1:1'b0; endmodule
刷新模块
module sdram_aref( input clk, input rst_n, input aref_en, output reg [3:0] cmd_reg, output reg end_aref ); reg [3:0] aref_cnt; reg flag_aref; localparam AREF=4'b0001; localparam NOP =4'b0111; always@(posedge clk, negedge rst_n) if(!rst_n) flag_aref<=1'b0; else if(aref_en==1'b1) flag_aref<=1'b1; else if(aref_cnt==4'd12) flag_aref<=1'b0; else flag_aref<=flag_aref; always@(posedge clk, negedge rst_n) if(!rst_n) aref_cnt<=4'd0; else if(aref_cnt==4'd12) aref_cnt<=4'd0; else if(flag_aref==1'b1) aref_cnt<=aref_cnt+1'b1; else aref_cnt<=4'd0; always@(*) begin case(aref_cnt) 4'd1: cmd_reg<=AREF; 4'd5: cmd_reg<=AREF; default: cmd_reg<=NOP; endcase end always@(posedge clk, negedge rst_n) if (!rst_n) end_aref<=1'b0; else if(aref_cnt==4'd12) end_aref<=1'b1; else end_aref<=1'b0; endmodule
SDRAM控制器顶层模块
1 module sdram_control_top( 2 input clk, 3 input rst_n, 4 input con_tran, 5 input [24:0] addr_in, 6 input req_wr_rd, 7 input [15:0] dq_wr, 8 output wire [1:0] sdram_dqm, 9 output wire sdram_clk, 10 output wire sdram_cke, 11 output wire sdram_cs_n, 12 output wire sdram_ras_n, 13 output wire sdram_cas_n, 14 output wire sdram_we_n, 15 output wire [15:0] dq_rd, 16 output reg [12:0] sdram_addr, 17 output reg [1:0] sdram_bank_addr, 18 inout wire [15:0] sdram_dq_in, 19 output wire addr_ready, 20 output wire flag_dq_wr, 21 output wire idle_sdram, 22 output reg req_send 23 ); 24 25 26 wire aref_req; 27 reg wr_rd_en; 28 wire [3:0] cmd_wr_rd; 29 wire [12:0] addr_wr_rd; 30 wire [1:0] bank_addr_wr_rd; 31 wire end_wr_rd; 32 wire flag_aref_req; 33 wire aref_req_wr_rd; 34 35 wire [12:0] addr_init; 36 wire [1:0] bank_addr_init; 37 wire [3:0] cmd_init; 38 wire end_init; 39 wire flag_init; 40 41 42 reg aref_en; 43 wire [3:0] cmd_aref; 44 wire end_aref; 45 46 reg [3:0] state; 47 reg [3:0] sd_cmd; 48 49 localparam NOP=4'b0111; 50 51 sdram_rd_wr U1( 52 .clk (clk), 53 .rst_n (rst_n), 54 .aref_req (aref_req_wr_rd), 55 .wr_rd_en (wr_rd_en), 56 .con_tran (con_tran), 57 .addr_in (addr_in), 58 .cmd_reg (cmd_wr_rd), 59 .sdram_addr (addr_wr_rd), 60 .sdram_bank_addr(bank_addr_wr_rd), 61 .flag_dq_wr (flag_dq_wr), 62 .addr_ready (addr_ready), 63 .end_wr_rd (end_wr_rd), 64 .flag_aref_req (flag_aref_req) 65 ); 66 67 sdram_init U2( 68 .clk (clk), 69 .rst_n (rst_n), 70 .init_addr (addr_init), 71 .bank_addr (bank_addr_init), 72 .cmd_reg (cmd_init), 73 .end_init (end_init), 74 .flag_init (flag_init) 75 ); 76 77 aref_cunter U3( 78 .clk (clk), 79 .rst_n (rst_n), 80 .end_init (end_init), 81 .aref_req (aref_req) 82 ); 83 84 sdram_aref U4( 85 .clk (clk), 86 .rst_n (rst_n), 87 .aref_en (aref_en), 88 .cmd_reg (cmd_aref), 89 .end_aref (end_aref) 90 ); 91 92 localparam ST_IDLE =4'b0001, 93 ST_AREF =4'b0010, 94 ST_WR_RD=4'b0100, 95 ST_INIT =4'b1000; 96 97 always@(posedge clk,negedge rst_n) 98 if(!rst_n) 99 state<=ST_INIT; 100 else case(state) 101 ST_INIT: if(end_init==1'b1) 102 state<=ST_IDLE; 103 else 104 state<=ST_INIT; 105 ST_IDLE: if(aref_req==1'b1) 106 state<=ST_AREF; 107 else if(req_wr_rd==1'b1||con_tran==1'b1) 108 state<=ST_WR_RD; 109 else 110 state<=ST_IDLE; 111 ST_AREF: if(end_aref==1'b1) 112 state<=ST_IDLE; 113 else 114 state<=ST_AREF; 115 ST_WR_RD: if(end_wr_rd==1'b1&&flag_aref_req==1'b1) 116 state<=ST_AREF; 117 else if(end_wr_rd==1'b1&&flag_aref_req==1'b0) 118 state<=ST_IDLE; 119 else 120 state<=ST_WR_RD; 121 default: state<=ST_INIT; 122 endcase 123 124 always@(*) begin 125 case(state) 126 ST_INIT: begin 127 sd_cmd <=cmd_init; 128 sdram_addr <=addr_init; 129 sdram_bank_addr<=bank_addr_init; 130 end 131 ST_IDLE: begin 132 sd_cmd <=NOP; 133 sdram_addr <=13'd0; 134 sdram_bank_addr<=2'd0; 135 end 136 ST_AREF: begin 137 sd_cmd <=cmd_aref; 138 sdram_addr <=13'd0; 139 sdram_bank_addr<=2'd0; 140 end 141 ST_WR_RD: begin 142 sd_cmd <=cmd_wr_rd; 143 sdram_addr <=addr_wr_rd; 144 sdram_bank_addr<=bank_addr_wr_rd; 145 end 146 default: begin 147 sd_cmd <=NOP; 148 sdram_addr <=13'd0; 149 sdram_bank_addr<=2'd0; 150 end 151 endcase 152 end 153 154 always@(posedge clk, negedge rst_n) 155 if(!rst_n) 156 wr_rd_en<=1'b0; 157 else if(state==ST_IDLE&&req_wr_rd==1'b1||state==ST_IDLE&&con_tran==1'b1) 158 wr_rd_en<=1'b1; 159 else 160 wr_rd_en<=1'b0; 161 162 always@(posedge clk, negedge rst_n) 163 if(!rst_n) 164 aref_en<=1'b0; 165 else if(state==ST_IDLE&&aref_req) 166 aref_en<=1'b1; 167 else if(end_wr_rd==1'b1&&flag_aref_req==1'b1) 168 aref_en<=1'b1; 169 else 170 aref_en<=1'b0; 171 172 assign aref_req_wr_rd=(aref_req==1'b1&&state==ST_WR_RD)?1'b1:1'b0; 173 assign idle_sdram=(state==ST_IDLE)?1'b1:1'b0; 174 175 assign {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n}=sd_cmd; 176 assign sdram_cke=1'b1; 177 assign sdram_clk=~clk; 178 assign sdram_dqm=2'b00; 179 assign sdram_dq_in=(flag_dq_wr==1'b1)?dq_wr:{16{1'bz}}; 180 assign dq_rd=sdram_dq_in; 181 182 183 always@(posedge clk, negedge rst_n) 184 if(!rst_n) 185 req_send<=1'b0; 186 else if(end_init==1'b1) 187 req_send<=1'b1; 188 else 189 req_send<=1'b0; 190 191 endmodule
上述代码可以组成一个完整的SDRAM控制器,上述代码不允许使用在商业或者论文中,本人保留一切权利。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/154672.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...