大家好,又见面了,我是你们的朋友全栈君。
同步动态随机存取内存(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控制器,上述代码不允许使用在商业或者论文中,本人保留一切权利。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/154672.html原文链接:https://javaforall.cn