程序设计思路

一.大体思路框架

  • PC通过串口助手,经过UART RX模块发送连续字节数据进入SDRAM_CTRL模块,SDRAM_CTRL模块里的WRfifo,接受RX传入的数据,WR_EN打开,同时传入地址和对应数据,通过满足Avalon时序(【WRfifo】读端:avm_waitrequest为低,非读空;写端:非写满,数据有效。【state】WRfifo读端rdusedw>=需要一次连续写入的数据量),传入Avalon_MM端口模块,再RD_EN打开,传入地址,经过Avalon端口读出SDRAM内部数据,传入SDRAM_CTRL模块里的RDfifo(【RDfifo】写端:avm_rd_data_vld 且非写满;读端:UART TX端非忙且非读空。),再传入UART TX端,PC通过串口助手接受到数据。
    • 使用Avalon_MM接口后,我们只需考虑SDRAM_Control模块(SDRAM控制模块)【内含WRfifo,RDfifo】,如何满足接收和发送数据到Avalon_MM接口即可,不用考虑SDRAM内部运行的过程。
    • 有四个状态,IDLE(空闲状态),WRITE(SDRAM写过程),READ(SDRAM读过程),DONE(结束)
展开查看相关代码


 
1
2
3
4
5
6
7
8
9

//状态转移条件
assign idle2read = (state_c == IDLE) && (rd_req) ; //当按键按下时,状态从IDLE跳转到READ
assign idle2write = (state_c == IDLE) && (rdusedw_sig >= 8'd3);//当WRfifo读端表示至少还有3个16bit数据后,状态从IDLE跳转到READ,开始进行读操作
assign read2done = (state_c == READ) && (end_cnt_rd_num);//当读出数据计数器记到结束条件(读出数据个数为3时),状态从READ跳转到DONE
assign write2done = (state_c == WRITE)&& (end_cnt_wr_num);//当写入数据计数器记到结束条件(写入数据个数为3时),状态从WRITE跳转到DONE
assign done2idle = (state_c == DONE) && 1'd1;//DONE状态直接跳转为IDLE


二.SDRAM从写入到读出的过程

  • 1. UART_RX接收到PC串口发送的8bit数据,传入SDRAM_Control模块里的WRfifo。
  • 2. WRfifo根据Avalon总线协议和WRfifo自身状态,控制WRfifo的读写使能的开启条件。
展开查看相关代码



  
1
2
3
4
5
6
7
//WRfifo
assign wrreq_sig = (din_vld) && (!wrfull_sig) ;
//WRfifo里的写使能开启条件为:从UART_RX输入到SDRAM_Control模块的8bit数据有效(din_vld),且WR_fifo写非空的状态下(!wrfull_sig),进行WRfifo的写操作。
assign rdreq_sig = (!rdempty_sig) && (!avm_waitrequest) && (state_c == WRITE);
//WRfifo里的读使能开启条件为:当WRfifo读非空的状态下(rdreq_sig),且上升沿对等待请求(avm_waitrequest)为低的状态下【因为只有在avm_waitrequest为低电平时数据才能传入Avalon_MM串口(当avm_waitrequest为高电平时SDRAM还没有准备好接受或者发送数据),进而传入SDRAM】, 且在读状态下,进行WRfifo数据的数据读出。


  • 3. WRfifo的读使能要在读状态下且avm_waitrequest为低,WRfifo非读空状态下才有效。当WRfifo读使能有效时,要确保WRfifo里读端的每个16bit数据与SDRAM所要写入的地址的同时输入到Avalon_MM接口模块。所以让地址(Addr)计数开启条件和写入Avalon_MM 16bit数据个数开始计数条件都在读状态下且avm_waitrequest为低时开始,当avm_waitrequest拉高时停止计数,保持地址和数据,当avm_waitrequest再一次为低电平时,继续写入16bit数据和对应地址。因为avm_waitrequest会在接受到wr_en或rd_en信号后拉高,当SDRAM能接受数据后才会拉低avm_waitrequest,拉低时的每个时钟周期就可以接受1个16bit数据与其对应的地址位。在此期间wr_en或rd_en都持续有效,等到连续数据全部输入或者传出后,跳出WRITE和READ状态,wr_en或rd_en才拉低。
展开查看相关代码



  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//cnt_wr_addr 写地址计数


reg [23:0] cnt_wr_addr; //24位宽地址
wire add_cnt_wr_addr;
wire end_cnt_wr_addr;
assign add_cnt_wr_addr = (state_c == WRITE) && (!avm_waitrequest); //地址计数开始条件为读状态下,且avm_waitrequest为低电平时。保证了在WRfifo读请求有效时,同时传入地址位。当在读状态下,avm_waitrequest为低电平的每个周期都写入1个地址。(为了方便我们把地址计数数据也当为地址数据(相当于在读状态下,avm_waitrequest为低电平的每个周期都输入从0开始到对应第几次的地址))
assign end_cnt_wr_addr = (add_cnt_wr_addr) && (cnt_wr_addr == 24'd10); //最多可以计数10个地址(相当于最多写入10个地址)【可以修改为大于或等于写入的数据个数的地址位,因为每个数据需要与对应的地址匹配】

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_wr_addr <= 24'd0;
end
else if (add_cnt_wr_addr) begin
if (end_cnt_wr_addr) begin
cnt_wr_addr <= 24'd0;
end
else cnt_wr_addr <= cnt_wr_addr +24'd1;
end
end


若地址计数个数设置为大于一次连续输入数据的个数,多余的地址可以作为串口端超过一次连续输入个数的数据的地址。


example:在PC串口助手端口一次性输入16个8bit数据,状态机从IDLE跳转到WRITE的条件为rdusedw_sig >= 8’d3
(相当于wrusedw_sig >= 8’d6【因为WRfifo写端为8bit数据,读端为16bit数据,写端每写入2个8bit数据,写端
wrusedw_sig加2,读端rdusedw_sig才加1】),写入数据次数到3的时候,状态机从WRITE跳到DONE,DONE直接跳转
到IDLE,因状态机从IDLE跳转到WRITE的条件为rdusedw_sig >= 8’d3,WRfifo读出了3个16bits数据,还剩5个16b
it数据,满足IDLE跳转到WRITE的条件,再次进入写状态,等待avm_waitrequest为低电平时,把剩余的地址按顺序和WR
fifo里后续的3个16bit数据,依次同时对应传输到Avalon_MM,这样循环,直到不满足跳转条件。

【特殊情况】{当数据大于剩余地址时,存储会出错,这需要考虑}

  • 4. 当WRfifo把3位16bit数据输入到Avalon_MM接口模块后,Avlaon会根据它自身协议把数据和对应的地址在同一时钟下写入SDRAM。
展开查看相关代码



  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

//cnt_wr_num
reg [4:0] cnt_wr_num;
wire add_cnt_wr_num;
wire end_cnt_wr_num;
assign add_cnt_wr_num = (state_c == WRITE) && (!avm_waitrequest) ;//数据输入计数开启条件为在WRTIE状态下且avm_waitrequest为低时计数
assign end_cnt_wr_num = (add_cnt_wr_num) && (cnt_wr_num == 5'd2); //计到3个数据后结束计数(跳转到DONE状态)

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_wr_num <= 5'd0;
end
else if (add_cnt_wr_num) begin
if (end_cnt_wr_num) begin
cnt_wr_num <= 5'd0;
end
else cnt_wr_num <= cnt_wr_num +1'd1;
end
end

  • 5. 当写入数据完成后,按下按键(按键控制读状态开始),当按键按下后,状态机从IDLE状态进入READ状态,与WRITE状态类似,在READ状态下,只需在avm_waitrequest为低时传入地址(ADDR)数据即可,Avalon_MM接口在rd_en信号有效,avm_waitrequest,且接受到地址后可以让SDRAM接受到读数据信号,但SDRAM内部会做一系列操作,可能从SDRAM读出数据时,READ状态已经过了,所以RDfifo的写请求(wrreq)条件为Avalon数据有效(avm_rd_data_vld)并且RDfifo非写满(!wrfull)状态,并不需要保证在读状态。RDfifo读端的读使能条件就很简单了,是串口发送模块非忙(!nrdy) 且RDfifo非读空 (!rdempty) 时就行。
展开查看相关代码



  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//rdfifo


wire [7:0] q_sig_2;
wire rdreq_sig_2;
wire rdempty_sig_2;
wire wrreq_sig_2;
wire wrfull_sig_2;


reg [15:0]dout_r;
reg dout_vld_r;


always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dout_r <= 0 ;
dout_vld_r <= 0;
end
begin
dout_r <= q_sig_2;
dout_vld_r <= rdreq_sig_2;
end
end
assign dout = dout_r;
assign dout_vld = dout_vld_r;//输出数据和输出有效信号同时延迟一拍,保证传入串口发送模块的数据稳定,也保证了有效数据信号和有效数据同步


assign rdreq_sig_2 = (!nrdy) && (!rdempty_sig_2) ;
assign wrreq_sig_2 = (avm_rd_data_vld) && (!wrfull_sig_2) ; //输出数据时,可能已经不是在读状态了

  • wr_en和rd_en的条件分别读写状态和读状态(因为读,写使能是低电平有效,所以取反)。虽然拉高了读写状态,但是只有在avm_waitrequest为低才有数据的传输,写状态结束后已经把数据传入了Avlaon,【特别】读状态结束后,数据不一定能传输完成,因为指令虽传入SDRAM,但SDRAM输出数据还有一段时间。上面已经说过了,这里就不再累述。
展开查看相关代码



  
1
2
3
4
//wr_en,rd_en
assign avm_wr_n = !(state_c == WRITE);//输出
assign avm_rd_n = !(state_c == READ);//输出

  • 地址(ADDR)因为只有一条线,所以需要读写共用一条地址线。
展开查看相关代码



  
1
2
3
4
5
6
7
8
//addr有效地址位数据

wire [23:0] addr;

assign avm_addr = addr;

assign addr = ({24{state_c == READ}} & cnt_rd_addr) | ({24{state_c == WRITE}} & cnt_wr_addr) ;//有效地址位

程序代码

Avalon_MM控制模块代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
module sdram_ctrl (
input sys_clk_in,
input sys_clk_out,
input rst_n,

//pll
input clk,

//uart_rx
input [7:0]din,
input din_vld,

//uart_tx
output [7:0]dout,
output dout_vld,
input nrdy,

//key_debounce
input rd_req,

//sdram_interface
//output [1:0]avm_byteenable,
output [23:0]avm_addr,
output avm_wr_n,
output [15:0]avm_wr_data,
output avm_rd_n,
input [15:0]avm_rd_data,
input avm_rd_data_vld,
input avm_waitrequest
);



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


localparam IDLE = 4'b0001,
READ = 4'b0010,
WRITE = 4'b0100,
DONE = 4'b1000;


wire idle2read;
wire idle2write;
wire read2done;
wire write2done;
wire done2idle;



//////////////////////////////////////////////////////////////////////////////////////////////
//cnt_wr_addr


reg [23:0] cnt_wr_addr;
wire add_cnt_wr_addr;
wire end_cnt_wr_addr;
assign add_cnt_wr_addr = (state_c == WRITE) && (!avm_waitrequest);
assign end_cnt_wr_addr = (add_cnt_wr_addr) && (cnt_wr_addr == 24'd10);


always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_wr_addr <= 24'd0;
end
else if (add_cnt_wr_addr) begin
if (end_cnt_wr_addr) begin
cnt_wr_addr <= 24'd0;
end
else cnt_wr_addr <= cnt_wr_addr +24'd1;
end
end


//////////////////////////////////////////////////////////////////////////////////////////////
//cnt_rd_addr


reg [23:0] cnt_rd_addr;
wire add_cnt_rd_addr;
wire end_cnt_rd_addr;
assign add_cnt_rd_addr = (state_c == READ) && (!avm_waitrequest);
assign end_cnt_rd_addr = (add_cnt_rd_addr) && (cnt_rd_addr == 24'd10);


always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_rd_addr <= 24'd0;
end
else if (add_cnt_rd_addr) begin
if (end_cnt_rd_addr) begin
cnt_rd_addr <= 24'd0;
end
else cnt_rd_addr <= cnt_rd_addr +24'd1;
end
end



//////////////////////////////////////////////////////////////////////////////////////////////
//addr有效地址位数据

wire [23:0] addr;

assign avm_addr = addr;

assign addr = ({24{state_c == READ}} & cnt_rd_addr) | ({24{state_c == WRITE}} & cnt_wr_addr) ;//有效地址位


//////////////////////////////////////////////////////////////////////////////////////////////
//cnt_wr_num


reg [4:0] cnt_wr_num;
wire add_cnt_wr_num;
wire end_cnt_wr_num;
assign add_cnt_wr_num = (state_c == WRITE) && (!avm_waitrequest) ;
assign end_cnt_wr_num = (add_cnt_wr_num) && (cnt_wr_num == 5'd2);

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_wr_num <= 5'd0;
end
else if (add_cnt_wr_num) begin
if (end_cnt_wr_num) begin
cnt_wr_num <= 5'd0;
end
else cnt_wr_num <= cnt_wr_num +1'd1;
end
end


//////////////////////////////////////////////////////////////////////////////////////////////
//cnt_rd_num


reg [4:0] cnt_rd_num;
wire add_cnt_rd_num;
wire end_cnt_rd_num;
assign add_cnt_rd_num = (state_c == READ) && (!avm_waitrequest);
assign end_cnt_rd_num = (add_cnt_rd_num) && (cnt_rd_num == 5'd2);

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_rd_num <= 5'd0;
end
else if (add_cnt_rd_num) begin
if (end_cnt_rd_num) begin
cnt_rd_num <= 5'd0;
end
else cnt_rd_num <= cnt_rd_num +1'd1;
end
end


//////////////////////////////////////////////////////////////////////////////////////////////
//fifo连线


wire wrfull_sig;
wire wrreq_sig;
wire [7:0] wrusedw_sig;
wire [6:0] rdusedw_sig;


//////////////////////////////////////////////////////////////////////////////////////////////
//状态转移条件


assign idle2read = (state_c == IDLE) && (rd_req) ;
assign idle2write = (state_c == IDLE) && (rdusedw_sig >= 8'd3);
assign read2done = (state_c == READ) && (end_cnt_rd_num);
assign write2done = (state_c == WRITE)&& (end_cnt_wr_num);
assign done2idle = (state_c == DONE) && 1'd1;


//////////////////////////////////////////////////////////////////////////////////////////////
//时序描述状态转移


always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_c <= IDLE ;
end
else state_c <= state_n ;
end



//////////////////////////////////////////////////////////////////////////////////////////////
//组合逻辑描述状态转移


always @(*) begin
case (state_c)
IDLE :
begin
if (idle2read) begin
state_n = READ;
end
else if (idle2write) begin
state_n = WRITE;
end
else state_n = state_c;
end

READ :
begin
if (read2done) begin
state_n = DONE;
end
else state_n = state_c;
end

WRITE :
begin
if (write2done) begin
state_n = DONE;
end
else state_n = state_c;
end

DONE :
begin
if (done2idle) begin
state_n = IDLE;
end
else state_n = state_c;
end

default: state_n =IDLE;
endcase
end


//////////////////////////////////////////////////////////////////////////////////////////////
//输出端口赋值

wire [15:0]avm_wr_data_w;

assign avm_wr_n = !(state_c == WRITE);//输出
assign avm_rd_n = !(state_c == READ);//输出


//////////////////////////////////////////////////////////////////////////////////////////////
//rdfifo


wire [7:0] q_sig_2;
wire rdreq_sig_2;
wire rdempty_sig_2;
wire wrreq_sig_2;
wire wrfull_sig_2;


reg [15:0]dout_r;
reg dout_vld_r;


always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dout_r <= 0 ;
dout_vld_r <= 0;
end
begin
dout_r <= q_sig_2;
dout_vld_r <= rdreq_sig_2;
end
end
assign dout = dout_r;
assign dout_vld = dout_vld_r;


assign rdreq_sig_2 = (!nrdy) && (!rdempty_sig_2) ;
assign wrreq_sig_2 = (avm_rd_data_vld) && (!wrfull_sig_2) ; //输出数据时,可能已经不是在读状态了


//////////////////////////////////////////////////////////////////////////////////////////////
//wrfifo

wire rdreq_sig;
wire rdempty_sig;
assign wrreq_sig = (din_vld) && (!wrfull_sig) ;
assign rdreq_sig = (!rdempty_sig) && (!avm_waitrequest) && (state_c == WRITE);



//////////////////////////////////////////////////////////////////////////////////////////////
assign avm_wr_data = avm_wr_data_w;




fifo_1 fifo_1_inst (
.aclr ( !rst_n ),
.data ( din ),
.rdclk ( clk ),
.rdreq ( rdreq_sig ),
.wrclk ( sys_clk_in ),
.wrreq ( wrreq_sig ),
.q ( avm_wr_data_w ),
.rdempty ( rdempty_sig ),
.rdfull ( rdfull_sig ),
.rdusedw ( rdusedw_sig ),
.wrempty ( wrempty_sig ),
.wrfull ( wrfull_sig ),
.wrusedw ( wrusedw_sig )
);



wire [6:0] rdusedw_sig_2;
wire [5:0] wrusedw_sig_2;
fifo_2 fifo_2_inst (
.aclr ( !rst_n ),
.data ( avm_rd_data ),
.rdclk ( sys_clk_out ),
.rdreq ( rdreq_sig_2 ),
.wrclk ( clk ),
.wrreq ( wrreq_sig_2 ),
.q ( q_sig_2 ),
.rdempty ( rdempty_sig_2 ),
.rdfull ( rdfull_sig_2 ),
.rdusedw ( rdusedw_sig_2 ),
.wrempty ( wrempty_sig_2 ),
.wrfull ( wrfull_sig_2 ),
.wrusedw ( wrusedw_sig_2 )
);

endmodule

SDRAM_TOP模块代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
module sdram_top (
input sys_clk ,
input rst_n ,

//uart_rx
input uart_txd ,

//uart_tx
output uart_rxd ,

//key_debounce
input key_in ,

//pll to sdram
output sdram_ctrl_clk ,

//sdram_interface
output [12:0]mem_addr ,
output [1:0]mem_ba ,
output mem_cas_n ,
output mem_cs_n ,
output mem_cke ,
output mem_ras_n ,
output [1:0]mem_dqm ,
output mem_we_n ,
inout [15:0]mem_dq

);

// wire [15:0]mem_dq_in;
// wire [15:0]mem_dq_out;
// wire mem_dq_en;
//
// assign mem_dq_in = mem_dq;
// assign mem_dq = (mem_dq_en)?mem_dq_out:1'dz;
//////////////////////////////////////////////////////////////////////////////////////////////


//uart_rx to sdram_ctrl
wire [7:0]rx_dout;
wire rx_dout_vld;


//uart_tx to sdram_ctrl
wire [7:0]tx_din;
wire tx_din_vld;
wire nrdy;


//key_debounce to sdram_ctrl
wire key_out;


//sdram_ctrl to sdram_interface
//wire [1:0]avm_byteenable;
wire [23:0]avm_addr ;
wire avm_wr_n ;
wire [15:0]avm_wr_data ;
wire avm_rd_n ;
wire [15:0]avm_rd_data ;
wire avm_rd_data_vld ;
wire avm_waitrequest ;

//pll to sdram_ctrl sdram_interface
wire sdram_clk ;

//////////////////////////////////////////////////////////////////////////////////////////////


key_debounce u_key_debounce(
/*input*/ .sys_clk(sys_clk) ,
/*input*/ .rst_n(rst_n) ,
/*input*/ .key(key_in) ,
/*output*/ .keyflag(key_out)
);


uart_rx u_uart_rx(
/*input*/ .sys_clk(sys_clk) ,
/*input*/ .rst_n(rst_n) ,
/*input*/ .rx(uart_txd) ,
/*output [7:0]*/.uart_rx_data(rx_dout) ,
/*output*/ .uart_rx_lvd(rx_dout_vld)
);


uart_tx u_uart_tx(
/*input*/ .sys_clk(sys_clk) ,
/*input*/ .rst_n(rst_n) ,
/*input [7:0]*/ .fifo_data_i(tx_din) ,
/*input*/ .tx_data_lvd_i(tx_din_vld) ,
/*output*/ .busy(nrdy) ,
/*output*/ .tx_data(uart_rxd)
);


sdram_ctrl u_sdram_ctrl(
/*input*/ .sys_clk_in(sys_clk),
/*input*/ .sys_clk_out(sys_clk),
/*input*/ .rst_n(rst_n),

//pll
/*input*/ .clk(sdram_clk),

//uart_rx
/*input [7:0]*/ .din(rx_dout),
/*input*/ .din_vld(rx_dout_vld),

//uart_tx
/*output [7:0]*/ .dout(tx_din),
/*output*/ .dout_vld(tx_din_vld),
/*input*/ .nrdy(nrdy),

//key_debounce
/*input*/ .rd_req(key_out),

//sdram_interface
//*output [1:0]*/ .avm_byteenable(avm_byteenable),
/*output [23:0]*/ .avm_addr(avm_addr),
/*output*/ .avm_wr_n(avm_wr_n),
/*output [15:0]*/ .avm_wr_data(avm_wr_data),
/*output*/ .avm_rd_n(avm_rd_n),
/*input [15:0]*/ .avm_rd_data(avm_rd_data),
/*input*/ .avm_rd_data_vld(avm_rd_data_vld),
/*input*/ .avm_waitrequest(avm_waitrequest)
);


//Avalon_MM IP调用
sdram u0 (
.clk_clk (sdram_clk), // clk.clk
.reset_reset_n (rst_n), // reset.reset_n
.avalon_slave_address (avm_addr), // avalon_slave.address
.avalon_slave_byteenable_n (2'b00), // .byteenable_n
.avalon_slave_chipselect (1'b1), // .chipselect
.avalon_slave_writedata (avm_wr_data), // .writedata
.avalon_slave_read_n (avm_rd_n), // .read_n
.avalon_slave_write_n (avm_wr_n), // .write_n
.avalon_slave_readdata (avm_rd_data), // .readdata
.avalon_slave_readdatavalid (avm_rd_data_vld), // .readdatavalid
.avalon_slave_waitrequest (avm_waitrequest), // .waitrequest
.sdram_mem_addr (mem_addr), // sdram_mem.addr
.sdram_mem_ba (mem_ba), // .ba
.sdram_mem_cas_n (mem_cas_n), // .cas_n
.sdram_mem_cke (mem_cke), // .cke
.sdram_mem_cs_n (mem_cs_n), // .cs_n
.sdram_mem_dq (mem_dq ), // .dq
.sdram_mem_dqm (mem_dqm), // .dqm
.sdram_mem_ras_n (mem_ras_n), // .ras_n
.sdram_mem_we_n (mem_we_n) // .we_n
); //相当于下面的sdram_interface模块



//sdram_interface u_sdram_interface(
// /*input*/ .rst_n(rst_n),
//
// //pll
// /*input*/ .clk(sdram_ctrl_clk),
//
// //sdram_ctrl
// /*input [1:0]*/ .avs_byteenable(avm_byteenable),
// /*input [23:0]*/ .avs_addr(avm_addr),
// /*input*/ .avs_wr_n(avm_wr_n),
// /*input [15:0]*/ .avs_wr_data(avm_wr_data),
// /*input*/ .avs_rd_n(avm_rd_n),
// /*output [15:0]*/ .avs_rd_data(avm_rd_data),
// /*output*/ .avs_rd_data_vld(avm_rd_data_vld),
// /*output*/ .avs_waitrequest(avm_waitrequest),
//
// //sdram
// /*output [12:0]*/ .mem_addr(mem_addr),
// /*output [1:0]*/ .mem_ba(mem_ba),
// /*output*/ .mem_cas_n(mem_cas_n),
// /*output*/ .mem_cke(mem_cke),
// /*output*/ .mem_cs_n(mem_cs_n),
// /*output*/ .mem_ras_n(mem_ras_n),
// /*output [15:0]*/ .mem_dq_out(mem_dq_out),
// /*output*/ .mem_dq_en(mem_dq_en),
// /*input [15:0]*/ .mem_dq_in(mem_dq_in),
// /*output [1:0]*/ .mem_dqm(mem_dqm),
// /*output*/ .mem_we_n(mem_we_n)
//
//;



my_pll my_pll_inst (
.areset ( !rst_n ),
.inclk0 ( sys_clk ),
.c0 ( sdram_clk ),
.c1 ( sdram_ctrl_clk),//偏移75
.locked ( locked_sig )
);

endmodule


UART_TX模块代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
module uart_tx (
input sys_clk,
input rst_n,
input [7:0]fifo_data_i,
input tx_data_lvd_i,
output busy,
output tx_data
);


///////////////////////////////////////////////////////////////////////////////////////////

parameter TX_BAUD_MAX = 16'd5208;
parameter TX_BIT_MAX = 4'd9 ;


reg [15:0]tx_baud ;
reg [3:0] tx_bit ;
reg tx_data_flag ;


wire add_tx_baud ;
wire end_tx_baud ;
wire add_tx_bit ;
wire end_tx_bit ;

assign add_tx_baud = tx_data_flag ;
assign end_tx_baud = add_tx_baud && ( tx_baud == TX_BAUD_MAX - 16'd1 ) ;

assign add_tx_bit = end_tx_baud ;
assign end_tx_bit = add_tx_bit && (tx_bit == TX_BIT_MAX) ;
assign busy = tx_data_flag ;


///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
tx_baud <= 16'd0;
end
else if (add_tx_baud) begin
if (end_tx_baud) begin
tx_baud <= 16'd0;
end
else tx_baud <= tx_baud + 16'd1;
end //baud计数
end


///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
tx_bit <= 4'd0;
end
else if (add_tx_bit) begin
if (end_tx_bit) begin
tx_bit <= 4'd0;
end
else tx_bit <= tx_bit + 4'd1;
end //bit计数
end


///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
tx_data_flag <= 1'd0;
end
else if (tx_data_lvd_i) begin
tx_data_flag <= 1'd1;
end
else if (end_tx_bit) begin
tx_data_flag <= 1'd0;
end //baud加数标志
end


///////////////////////////////////////////////////////////////////////////////////////////


reg [9:0]tx_data_r;



///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
tx_data_r <= 10'h3ff;
end
else if ( tx_data_lvd_i ) begin
tx_data_r <= {1'b1,fifo_data_i,1'b0}; //先进先出
end
end //把有效的8位数据转换为标准10位数据


///////////////////////////////////////////////////////////////////////////////////////////


reg tx_data_o ;
assign tx_data = tx_data_o ;


///////////////////////////////////////////////////////////////////////////////////////////
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
tx_data_o <= 1'b1;
end
else if (tx_baud == 16'd1) begin
tx_data_o <= tx_data_r[tx_bit];
end
end








endmodule




UART_RX模块代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
module uart_rx (
input sys_clk ,
input rst_n ,
input rx ,
output [7:0]uart_rx_data ,
output uart_rx_lvd
);



////////////////////////////////////////////////////////////////////////////////////////////
parameter IDLE = 4'b0001 ,
START = 4'b0010 ,
RD_DATA = 4'b0100 ,
STOP = 4'b1000 ; //参数声明
////////////////////////////////////////////////////////////////////////////////////////////
wire idle2start ;
wire start2idle ;
wire start2rd_data ;
wire rd_data2stop ;
wire stop2idle ; //内部参数声明
wire nedge ;
////////////////////////////////////////////////////////////////////////////////////////////
reg [3:0]state_c ;
reg [3:0]state_n ;
////////////////////////////////////////////////////////////////////////////////////////////
reg[9:0]uart_rx_data_r ;
////////////////////////////////////////////////////////////////////////////////////////////
reg [2:0]rx_r ;
////////////////////////////////////////////////////////////////////////////////////////////
reg [15:0]cnt_baud ;
wire add_cnt_baud ;
wire end_cnt_baud ;
////////////////////////////////////////////////////////////////////////////////////////////
reg [3:0]cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
////////////////////////////////////////////////////////////////////////////////////////////
assign nedge = (!rx_r[1])&&(rx_r[2]) ;
////////////////////////////////////////////////////////////////////////////////////////////
assign idle2start = (state_c == IDLE) && (nedge ) ;
assign start2idle = (state_c == START) && (uart_rx_data_r[9] ) && (end_cnt_baud) ;
assign start2rd_data = (state_c == START) && (~uart_rx_data_r[9]) && (end_cnt_baud) ;
assign rd_data2stop = (state_c == RD_DATA) && (cnt_bit == 8 ) && (end_cnt_baud) ;
assign stop2idle = (state_c == STOP) && (end_cnt_bit ) ;
////////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
state_c <= IDLE ;
end
else
state_c <= state_n;
end //时序逻辑


////////////////////////////////////////////////////////////////////////////////////////////


always @(*) begin
case (state_c)
IDLE :begin
if (idle2start) begin
state_n = START ;
end
else state_n = IDLE ;
end

START :begin
if (start2rd_data) begin
state_n = RD_DATA;
end
else if (start2idle) begin
state_n = IDLE ;
end
else
state_n = START ;
end

RD_DATA:begin
if (rd_data2stop) begin
state_n = STOP ;
end
else
state_n = RD_DATA;
end

STOP :begin
if (stop2idle) begin
state_n = IDLE ;
end
else
state_n = STOP ;
end
default: state_n = IDLE ;
endcase
end //次态的组合逻辑


///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
rx_r <= 3'd1;
end
else begin
rx_r[0] <= rx;
rx_r[1] <= rx_r[0];
rx_r[2] <= rx_r[1]; //打拍检测下降沿
end
end


///////////////////////////////////////////////////////////////////////////////////////////


// reg add_cnt_baud_flag;


///////////////////////////////////////////////////////////////////////////////////////////


// always @(posedge sys_clk or negedge rst_n ) begin
// if (!rst_n) begin
// add_cnt_baud_flag <= 1'd0;
// end
// else if (idle2start) begin
// add_cnt_baud_flag <= 1'd1;
// end
// else if (start2idle) begin
// add_cnt_baud_flag <= 1'd0; //当idle2start开始计数,start2idle,stop2idle计数停止
// end
// else if (stop2idle) begin
// add_cnt_baud_flag <= 1'd0;
// end
// end //计数标志信号
//state_c !=IDLE代替了add_cnt_baud_flag

///////////////////////////////////////////////////////////////////////////////////////////


parameter BAUD_MAX = 16'd5208 ;
assign add_cnt_baud = (state_c !=IDLE) ;
assign end_cnt_baud = add_cnt_baud && (cnt_baud == BAUD_MAX - 16'd1) ;


///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
cnt_baud <= 16'd0;
end
else if (start2idle) begin
cnt_baud <= 16'd0;
end
else if (add_cnt_baud) begin
if (end_cnt_baud) begin
cnt_baud <= 16'd0;
end
else cnt_baud <= cnt_baud + 16'd1;
end
end
//baud计数

///////////////////////////////////////////////////////////////////////////////////////////


parameter BIT_MAX = 4'd9 ;
assign add_cnt_bit = end_cnt_baud ;
assign end_cnt_bit = add_cnt_bit && (cnt_bit == BIT_MAX);


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
cnt_bit <= 4'd0;
end
else if (start2idle) begin
cnt_bit <= 4'd0;
end
else if (add_cnt_bit) begin
if (end_cnt_bit) begin
cnt_bit <= 4'b0;
end
else cnt_bit <= cnt_bit + 4'd1;
end //bit计数
end


///////////////////////////////////////////////////////////////////////////////////////////


assign uart_rx_data = uart_rx_data_r[8:1];


///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
uart_rx_data_r <= 10'd0;
end
else if (start2idle) begin
uart_rx_data_r <= 10'd0;
end
else if (cnt_baud == BAUD_MAX>>1) begin
uart_rx_data_r <= {rx,uart_rx_data_r[9:1]};
end

end //把每个baud中间的值寄存在uart_rx_data_r


///////////////////////////////////////////////////////////////////////////////////////////


reg uart_rx_lvd_r ;
assign uart_rx_lvd = uart_rx_lvd_r ;

///////////////////////////////////////////////////////////////////////////////////////////


always @(posedge sys_clk or negedge rst_n ) begin
if (!rst_n) begin
uart_rx_lvd_r <= 1'b0;
end
else if (stop2idle) begin
uart_rx_lvd_r <= 1'b1;
end
else uart_rx_lvd_r <= 1'b0;
end //有效标志拉高

//输出逻辑

///////////////////////////////////////////////////////////////////////////////////////////


endmodule

key_debounce模块代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
module key_debounce (
input sys_clk ,
input rst_n ,
input key ,
output keyflag
);
parameter TIME_20MS = 20'd1_000_000 ;



reg [25:0] cnt_20ms ;
reg add_flag ;
reg key_r0 ;
reg key_r1 ;
reg keyflag_r ;

wire add_cnt_20ms ;
wire end_cnt_20ms ;
wire nedge ;



assign nedge = !key_r0 && key_r1 ;
assign add_cnt_20ms = add_flag ;
assign end_cnt_20ms = add_flag && (cnt_20ms == TIME_20MS -20'd1) ;
assign keyflag = keyflag_r ;



always @(posedge sys_clk or negedge rst_n) begin
if(!rst_n)begin
cnt_20ms <= 20'd0;
end else if(nedge)begin
cnt_20ms <= 20'd0;
end else if(add_cnt_20ms)begin
if(end_cnt_20ms)begin
cnt_20ms <= 20'd0;
end else cnt_20ms <= cnt_20ms + 20'd1;
end
end



always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
key_r0 <= 1'd1;
key_r1 <= 1'd1;
end else begin
key_r0 <= key;
key_r1 <= key_r0;
end
end



always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
add_flag <= 1'd0;
end else if(nedge)begin
add_flag <= 1'd1;
end else if(end_cnt_20ms)begin
add_flag <= 1'd0;
end
end



always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
keyflag_r <= 1'd0;
end else if (end_cnt_20ms) begin
keyflag_r <= ~key;
end else keyflag_r <= 1'd0;

end



endmodule




testbench代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
`timescale 1ns/1ps
module sdram_top_tb ();
/*input*/ reg sys_clk;
/*input*/ reg rst_n;

//uart_rx
/*input*/reg uart_txd;

//uart_tx
/*output*/wire uart_rxd;

//key_debounce
/*input*/ reg key_in;

//pll to sdram
/*output*/ wire sdram_ctrl_clk;

//sdram_interface
/*output [12:0]*/wire [12:0]mem_addr;
/*output [1:0]*/wire [1:0]mem_ba;
/*output*/ wire mem_cas_n;
/*output*/ wire mem_cs_n;
/*output*/ wire mem_cke;
/*output*/ wire mem_ras_n;
/*output [1:0]*/wire [1:0]mem_dqm;
/*output*/wire mem_we_n;
/*inout [15:0]*/wire [15:0]mem_dq;


/* wire [15:0] sdram_dq_in ;
wire [15:0] sdram_dq_out ;
wire sdram_dq_out_en ;

assign sdram_dq_in = sdram_mem_dq;
assign sdram_mem_dq = sdram_dq_out_en?sdram_dq_out:16'hzzzz; */
defparam u_sdram_top.u_key_debounce.TIME_20MS = 10;
defparam u_sdram_top.u_uart_rx.BAUD_MAX = 100;
defparam u_sdram_top.u_uart_tx.TX_BAUD_MAX = 100;

//模块例化
sdram_top u_sdram_top(
/*input*/ .sys_clk(sys_clk),
/*input*/ .rst_n(rst_n),

//uart_rx
/*input*/ .uart_txd(uart_txd),

//uart_tx
/*output*/ .uart_rxd(uart_rxd),

//key_debounce
/*input*/ .key_in(key_in),

//pll to sdram
/*output*/ .sdram_ctrl_clk(sdram_ctrl_clk),

//sdram_interface
/*output [12:0]*/.mem_addr(mem_addr),
/*output [1:0]*/.mem_ba(mem_ba),
/*output*/ .mem_cas_n(mem_cas_n),
/*output*/ .mem_cs_n(mem_cs_n),
/*output*/ .mem_cke(mem_cke),
/*output*/ .mem_ras_n(mem_ras_n),
/*output [1:0]*/.mem_dqm(mem_dqm),
/*output*/ .mem_we_n(mem_we_n),
/*inout [15:0]*/.mem_dq(mem_dq)

);

sdr u_sdr(
/*input */.Clk (sdram_ctrl_clk ),
/*input */.Cke (mem_cke ),
/*input */.Cs_n (mem_cs_n ),
/*input */.Ras_n(mem_ras_n ),
/*input */.Cas_n(mem_cas_n ),
/*input */.We_n (mem_we_n ),
/*input */.Addr (mem_addr ),
/*input */.Ba (mem_ba ),
/*inout */.Dq (mem_dq ),
/*input */.Dqm (mem_dqm )
);

//产生时钟
localparam CLK_PERIOD = 20;//一个周期为20ns
initial sys_clk = 1'b0;//时钟初始值为0
always #(CLK_PERIOD/2) sys_clk=~sys_clk;//一个周期有0,1两个电平交互,always表示循环 ,#表示延时

//复位3个周期
initial begin
rst_n = 1'b0;//复位为0
#(CLK_PERIOD *3);//延时3个周期
rst_n = 1'b1;//将原有的低电平拉高为1,变为高电平,此后每隔3周期高低电平交互
// #10000;//运行10000ns之后停止运行
// $stop;
// #(CLK_PERIOD *2000);//停止运行
// $stop;
end

//激励--即输入
initial begin
//设置初始状态,按键未按下
key_in = 1'b1;
uart_txd =1'b1;
#3;
#(CLK_PERIOD *5);


repeat(6)begin //发开始位
uart_txd = 1'b0;
#(CLK_PERIOD *100);
//发数据位
repeat(8)begin
uart_txd = {$random};
#(CLK_PERIOD *100);
end
//发停止位
uart_txd = 1'b1;
#(CLK_PERIOD *100);
//空闲200
#(CLK_PERIOD *200);
end
@(negedge u_sdram_top.u_sdram_ctrl.avm_waitrequest);
#(CLK_PERIOD *200);
key_in = 1'b0;
#(CLK_PERIOD *200);
key_in = 1'b1;
//@(posedge u_sdram_top.u_sdram_ctrl.avm_rd_data_vld);
#(CLK_PERIOD *5000);
$stop;

end

endmodule