行列地址线被选中后,数据线(data_bit)直接和电容相连接。当写入时,数据线给电容充放电;读取时,电容将数据线拉高或者置低。
, |, c8 s/ U2 t" d
SDRAM 的全称即同步动态随机存储器(Synchronous Dynamic Random Access Memory);这里的同步是指其时钟频率与对应控制器的系统时钟频率相同,并且内部命令的发送与数据传输都是以该时钟为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失。
% I p! r9 _+ r/ Y9 }
SDR SDRAM中的SDR是指单数据速率,即每一根数据线上,每个时钟只传输一个bit的数据。SDR SDRAM的时钟频率可以达到100MHz以上,按照100MHz的速率计算,一片16位数据宽度的SDR SDRAM的读写数据带宽可以达到1.6Gbit/s。
0 l5 M3 K, h! r4 K- e6 R
SANXIN – B01的开发板上有一个容量为256Mbit(16M x 16bit)的SDR SDRAM(H57V2562GTR)。其内部存储时,分为了4个独立的区域(BANK),每个bank为4Mx16bit的存储空间;每个bank在存储时,按照二维的方式进行存储,利用行列来进行确定,有8192行(13bit地址线),有512列(9bit地址线),8192 x 512为4M的存储量。
5 |( W3 x% H$ h1 T7 T8 y, c# m7 o
在进行指定某个地址时,共需要2位bank地址,13位行地址,9位列地址,合计共24位地址。但是在SDR SDRAM的指定某个地址时,行地址和列地址不是同时给出,SDR SDRAM采用行列地址线复用,所以地址线合计为2(bank 地址)+13(行、列地址复用)。
. p) Q7 _ H6 l5 @6 D, O
SDR SDRAM需要时钟端和时钟使能端。SDR SDRAM所有的操作都依靠于此时钟;当时钟使能端无效时,SDR SDRAM自动忽略时钟上升沿。
# s% Y5 r- z9 f
SDR SDRAM拥有四个命令控制线,分别为CS、RAS、CAS、WE。组成的命令表如下:
1 z7 @1 M! o, R' z
0 c7 P" c8 J) P
/ T- P1 I' h6 d/ f* P
# Y# N7 i- x: [# L
* y6 E) Z# O Y8 G* i
在写入数据时,有时会出现不想对某8bit进行写入,就可以采用DQM进行控制。
& k! |9 V( w7 i2 O( H! [% v. J4 D
0 h% V& O# X7 M( b* o4 mSDR SDRAM的内部机构为:
6 E- |& Z* i# w0 j v* s' C) f
, w) G) {7 l/ i. M* E
' Q6 ~0 u3 l# R2 ]& g3 n/ L
- \( N7 e: n! Y2 A, f/ p b
2 |2 |, [+ i5 K% V
由于SDR SDRAM为DRAM,内部的存储都是靠电容进行保存数据,电容的保持数据的时间为64ms,SDR SDRAM每次只能够刷新一行,为了不丢失任何数据,所以要保证64ms内,将所有的行都要刷新一遍。
4 c, H' R' j2 ?% x1 M
SDR SDRAM支持读写的长度为1、2、4、8和一行(整页)。
0 l+ r- E; b* S" u4 I$ {+ d
具体的SDR SDRAM的介绍可以查看手册。下面只介绍几个相对重要的时序图。
" H5 I; I; X+ S- g' t5 ^; x" L
6 H$ J$ f2 z8 }5 m! @: V
在SDR SDRAM正常使用之前,需要进行初始化。初始化的时序图如下:
* \, G( a5 ]8 x: q" ^
6 _6 a% b+ V. P; Q u
) i9 W, w0 {5 ~( O0 E0 [8 b% @: u$ k
! \5 z. e2 @& |% p0 |5 Z
0 H) p3 j9 w" q& F
在PRECHARGE时,A10为高,表示选中所有的bank;A10为低,表示选中BA0、BA1所指定的bank。初始化中,A10置高。
% [ ]! a; Z2 z* e, m8 r4 F, z$ U
; a9 x) a! j' @, a在LOAD MOOE REGISTER中,采用地址线进行配置模式寄存器。说明如下:
" A y$ \; R( H4 h7 L3 x
0 |# n/ B! H5 y& S* V: E8 l
! i, e. B9 p& J- w' i6 f# [% t4 W; M7 i9 z8 K" \( R& p
7 f4 A- \ `) J9 E( i z# {
* X. F' x* Y- J0 p( v
在模式配置中,利用CL(CAS Latency)表示列选通潜伏期,利用BL(Burst Length)表示突发长度。
2 k' b. T. S- i' u( O
SDR SDRAM中有内部的刷新控制器和刷新的行计数器,外部控制器只需要保证在64ms之内进行8192次刷新即可。
4 I* K7 R w, M
) _/ v" W. e$ b4 a在进行PRECHARGE时,A10要为高电平。
+ ]& T" `) A8 F' o8 ?. G
3 [( h" v% C2 a3 j+ ?+ u
* O- Q3 I/ M% H' x0 v
9 ~4 D! o: a, g, f9 p
z$ k" } J5 v, p
SDR SDRAM中,我们可以在任意位置进行写入。写入的时序图如下:
* T" N7 a) G E! f k7 o' \( |% S# A
9 H% ~1 m. L' Q2 ]! q4 d4 H
' v3 U/ L M. x- B; [
. |: ~! H* M1 ?
( S' ~! v! t$ k5 M2 X, X' ]: Y
SDR SDRAM中,我们可以在任意位置进行读出。读出的时序图如下:
$ o% p: }4 _2 s7 h9 x) J
& s! z( G5 B2 x
) y! p; g0 I# C2 Q2 C
$ S/ {+ C; O; e: M
% }) l" Z, K8 S' p; e% G
在各个时序中的时序参数如下:
+ x& u! G6 Z6 G
0 D7 i/ j, k- [% z5 w
- ?4 B2 E6 C4 ^- ^) J0 a# y3 X5 p% O; [
) L) \+ n" G+ G/ i, y
& K" s1 Y3 R. y$ O7 {
- R) [ ?' C, A& P( A; R
) g# h. U) t6 V+ I
- 设计要求9 n( O7 h8 n# \" W6 P" k
设计一个突发长度为2,列选通潜伏期为2的SDR SDRAM的控制器。
* D/ ~: g4 H# n5 f, C1 z
- 设计分析
* t9 {$ }3 Q- S) Z7 Z. H+ O% t
该控制器共有四部分功能,初始化、刷新、写和读。四部分的执行控制采用一个模块来控制。
& z5 R6 Y) V" b: ]1 e1 T4 \6 Y
SDR SDRAM必须要进行初始化,初始化只用执行一次。然后启动一个计时器,等计时器达到后,进行刷新。在刷新的间隔中,根据读写的要求进行读写。
" d) y& b" b D3 i8 q8 \- _
四个模块都会对SDR SDRAM的命令线和地址线进行控制,所以输出时,采用多路选择器对齐进行选择输出。
" @9 W' K5 ?% M; ~! m0 c$ C$ z+ k5 D
四个模块按照对应的时序图进行编写代码即可。
% b: ^# l, i, H2 H) `1 P
- 架构设计和信号说明% v; I$ x# _. i: q
6 P8 f0 k( p. \' m7 J, p
该控制器命名为sdr_drive。
6 k( s' ?# E' o8 Q9 K5 t
/ V0 b' Y4 Q6 V" O! ]8 k
, I- l+ _, o& A$ i' Q
- l: K7 `% V% G- h" z
7 | Y& m; R; b5 h
pll_sdr(锁相环模块):产生驱动所需要的100MHz的时钟(0度相位)、SDR SDRAM所需要的100MHz的时钟(270度相位)、以及PLL锁定信号当作系统复位使用。
. ^- M0 H0 i5 u; R
timer(刷新计时器):当启动计时器后,开始计时,当计时到规定时间后,输出刷新请求,计数器直接清零计数计数。当控制器响应后,输出清除信号后,刷新请求拉低。
+ |+ O4 y6 r. k7 s& Y- t ?
refresh(刷新模块)、init(初始化模块)、sdr_write(写模块)、sdr_read(读模块):当启动模块后,按照规定的时序进行输出即可,然后输出完成信号。
+ L% F4 @ p. M# r6 m$ L: f
sdr_ctrl(控制模块):控制各个模块协调工作。
+ [# Y: v6 o, T; _* P d
mux4_1(四选一多路选择器模块):选择对应的bus总线作为输出。
, [- V" [0 j6 x ~, ~6 o6 ?
1 y6 J8 C+ q9 ?) I" d
*_bus的组成为:高四位为sdr_cs_n、sdr_ras_n、sdr_cas_n、sdr_we_n。然后是bank的两位,后续为13位的sdr_addr。
# E6 _2 P4 e3 r' c: P
4 ]& C: E5 X0 T2 h: N7 B! D
0 H% N" E# w ^4 X& u1 H
8 l; ] E5 C7 N$ G# O2 F
- @1 X" l. _9 @
: D& y% y% L' C# ]
, `" y9 d3 Y" S5 O5 ]' z" d5 g
6 z& a' n3 e2 b" T: q7 B
- sdr_drive_head声明
0 v" t8 s' F% t6 |5 F3 U) g4 ~ _
6 |1 q2 @$ q0 Q9 v将驱动中用到各种参数定义在该文件中。
w7 B+ c7 K8 N3 t
' n5 q! ~% c3 l9 i/ n3 j8 |9 G
+ J' ~2 o9 C$ T8 ~, Z) @. e, h
5 q7 k8 V. L" W
6 m( M [& y! g' g
- pll_sdr设计实现
' }. z* f) T* R# s
该模块为IP core,输出0相位的100MHz(系统时钟)和270相位的100MHz(SDR的时钟)。系统设计中,信号在上升沿输出;对于外部器件(相位调整为270),能够较好的满足建立和保持时间。
6 d+ ^0 Z2 B h* {! \* ]4 D
- init设计实现' X8 d' R6 Z G! d7 J1 `
该模块负责将SDR SDRAM进行初始化。上电延迟(PU_DELAY)设置为200us;预充电时间(Trp)设置为3个时钟周期(30ns);自刷新时间(TRFc)设置为7个时钟周期(70ns);模式寄存器应用时间(Tmrd)设置为3个时钟周期(30ns);突发长度为2;列选通潜伏期为3。
2 }% h, S+ s0 ~6 e
按照对应的初始化的时序图,做出如下设计。
) G: g* Y- b7 |5 @- W0 L: C
1 U9 m" m* t' ]2 x* J7 b( ^9 J本模块采用状态机的方式设计实现。
3 k! ~/ {+ `, {
5 ^ e5 L4 N+ B
7 c* X" l) c; s
/ [9 w* H% ?) m2 @# j9 P e
" ?! S8 H; G: `1 {6 G; [% X1 S
设计代码为:
" {9 o) @6 e8 M0 e7 K
, o) ]: Y2 [% w9 b
8 @$ ]3 a- A( N& A( |3 W. T9 Z. V
! E/ k# x& b8 l* D& B$ N" z
4 D7 ]2 M" |& u9 r
- timer设计实现
6 O: D2 u4 o' u, i* e% w8 ~* b, V
( {" ]0 [$ X [5 K& i$ _
SDR SDRAM内部构造为DRAM,需要不间断的刷新,要求64ms刷新一遍。每次刷新为一行,开发板上的SDR SDRAM共有8192行,平均需要7812.5ns刷新一次,我们选择7810刷新一次。
6 G4 n' }. u I6 z1 R6 `
0 f( ~& j9 b" B0 l& c7 T& B到达规定的刷新时间时,控制器有可能正在进行其他的操作。在设计时,达到时间后,发出刷新请求,当外部执行刷新后,将次请求清除。发出刷新请求的同时,计数器重新归零计数。
# x% j; |* p8 `) g) Z9 a6 m& N
8 Q" |8 x2 i0 \' a8 M: v+ k
; M4 S" t2 z+ _) i5 P
0 o! _, D9 z2 i
, P3 F0 z( q h" L, n
( w" R m8 b: h+ r( V1 `- B
- refresh设计实现
9 X* e4 U/ G& m, _8 c- H0 o
该模块负责刷新,按照对应的时序图进行控制即可。
+ a' M5 @* j1 t* M- n$ `# B
8 [1 q% |) s% J5 o# L- q该模块利用状态机的方式实现。状态转移图如下:
6 T4 [. @8 p8 D h' t" K$ t0 z
" E( P! O9 p* ^( @9 ~
+ n. v! I, N& u3 v1 S" [+ v; s9 \/ n# r2 v" V, `
5 L$ d5 }5 B3 r* ~' {9 l
) `, j5 Q' J$ ~! b* l
设计代码为:
& p/ ?6 ?+ E9 a
( q1 w4 h" @+ t* _& h
0 J' u( x" L8 c. c; W% A
1 ~- e$ g6 ~1 s1 z0 V; I
6 m4 U+ Z+ I# x5 J ^+ D
3 m1 H; H3 u" K# L
- sdr_write设计实现
# y' G) Y; V5 k7 ~2 Y( m
该模块负责将外部的数据写入到规定的地址中去。在SDR SDRAM中,每操作(读写)一次,都会引起该存储位的漏电,每次结束时,可以进行预充电。SDR SDRAM提供了自动预充电的机制,在读写命令时,sdr_addr[10]=1,即可自动预充电。在设计时,应该要为自动预充电预留出足够的时间。
5 t2 A# U# @- X7 S0 t
2 T! j4 M' y x5 U$ b5 q根据对应的写入时序图,利用状态机完成此设计。
, X0 {& [, Q: b+ m- \+ z
: z. K/ q: o# `6 P9 r+ T
* F8 Q6 ^/ ]) ^ u7 n
6 v7 R8 m; }$ }- Z" e2 R/ l
) ~% J t( G6 A% o; A
' n( ~8 i$ p' R$ ?, g% e1 k {
设计代码如下:
0 ]! B3 m* r4 {* M, V. x
7 b+ _" \5 o( X% z
- U1 r& X3 {/ K6 g! g) _" Y& \# O' q
4 P" P! T O. v7 Z$ q6 m* F
7 Y0 ^ T z6 u4 [! G- q+ J
- sdr_read设计实现% J0 Q9 R! B: Q9 C& ~. s" g
该模块负责从指定的地址中,将数据读出。
2 y L6 t* n& I0 ? ?) Y
, ?8 p7 Z% T5 M" q+ M' p+ w2 y
按照对应的读时序图即可实现功能,本模块采用状态机方式实现,状态转移图如下:
" U" \/ R2 K% g# k e. Y
2 f& {2 }3 D: i9 C, y0 i
; P. e0 L! ]! v% {! \9 C
: i4 L- _3 ^2 L9 m0 G Y5 E
/ V) Z- D6 q) H# R$ a
6 ~0 o9 Z' q4 I, t( w
设计代码为:
; E& \0 u/ @! i4 L2 t
6 F# }# [, S- J* W4 }) z
* i7 t' f& u2 b4 J& G% H
4 c0 d7 z5 Q$ w% K) e+ @( o$ [! r$ L* N' Z$ X2 V
" x4 ]0 ?" ?* o, A# d7 e! I% h& I
- mux4_1设计实现
; [8 _7 X/ d: p8 Y+ V1 A+ Z- A, p
该模块负责选择出对应的bus,然后将对应位作为输出即可。
6 \0 z8 L: M+ f# E# U' A! }. i
% b: Q- g) Y- u. J7 B' `8 R4 i3 g5 c
设计代码为:
8 K( v4 R m3 s$ {8 y! Y
6 \( {/ t9 h, W* a- d. ?9 {
, |5 ]$ f) o. |4 S: _) M1 A% ~3 w
+ E4 |* i3 m' n# q4 c- @6 y0 Y
7 x5 ]/ l* D7 L' m' L8 Y* o
- sdr_ctrl设计实现2 E! M1 E5 D; x) I: `8 ?. Y
) Q7 R, t8 r% f7 V
该模块负责调度整个控制器,利用状态机实现。
6 N: k' M/ [( c; Z# i2 a& d
. p" N: T/ t3 X. E# _
) _) ]; o8 D$ T) t/ x
$ ^& L. l6 a9 F- R2 ^1 ^
% M" b0 D ?5 F3 y: V: Y
设计代码为:
5 t0 O x6 q" V/ g
y& L$ q1 N7 `0 `9 J
+ {+ U4 m9 n7 E4 p+ B# q4 G# B: j5 k/ P* V! k" [4 U/ ]3 j
+ q* y) w6 z7 Q2 [
为了防止在进行刷新的起始部分丢失读写命令,所以在设计时,加入了缓存结构,只要有读写命令时,都会进行保存。在读写执行时,才会清除此命令。
+ A, m/ E5 O, i8 g4 A& v' n
- RTL仿真$ j' v+ V: u+ Z5 v3 H
2 C6 @& {( b; {) x# p2 p. ~为了能够仿真此设计,需要用到SDR SDRAM的仿真模型。仿真模型在msim的sdr_sim_module中,将其修改为行线为13bit,列为9bit,每个bank有4194304个存储空间。
: ]" h/ }/ U6 ]* R; a. f
& Y5 V9 f7 _+ Z
$ {6 c/ b$ B; |, T4 ]& ?
8 e* m, d1 j$ k6 e$ t
. r7 G; Y/ J; \* S+ R0 {1 U8 l) ~4 H; S
在仿真时,在第二个bank,第五行,第10列,写入一个随机值。然后读取出来。
, H; e U7 {4 t2 R/ _8 _2 O
# k* r7 v o1 `& i. M
仿真代码为:
6 N& L' Q j- q _. y6 z/ V
' j& ^6 k; i/ k& ~ F
' D0 l8 E! O; N' D* D' {
! F6 G( i6 {; K2 ]' H- G
8 t g- v/ F$ ~; T, D7 |( m# ^
这设置激励时,将tb文件和仿真模型文件同时加入添加文件中。
( c+ |0 ^* m- G$ x
8 \/ H- o9 I; t; | ?& u4 V
; A( G8 O! e, s# F2 _, K' g1 g( E) O t5 G
! W; `8 b& ^ G9 a) w' S3 v
在modelsim的报告界面会显示出具体的配置信息以及读写信息。
7 Z3 G2 N* g: ^; F( ? E* s
) o# k/ }1 a" m# B, p
2 M1 Y- G" u7 k- M7 R
/ r. n: A# W2 ^/ d6 U( p
2 Y, H( S- \) v/ p; F' ?: i! ^; t. E
从打印的报告中可以看出,在初始化时,列选通潜伏期为2,突发长度为2。在后续的读写时,在指定的位置,写入了13604,后续的一个位置为4629;在读出时,也正确的读出了数据。, C: L" @; S* A
* ^1 N. F" M5 g* ?
报告打印出写入数据,即认为写入成功;报告打印出读出数据,只能证明控制器将数据读出,并不表示控制器能把数据接收到。
! g/ S1 b. L6 a% h4 |5 v$ M; n
, ^# [: n( Q1 y
6 t: t: D: D& }! u" C( W3 l
* K& h1 U9 [% [% `
4 Q O; }* W/ U" ~
4 E. @1 n: f9 T/ g
2 e5 a* q0 d$ Q; h+ m$ j9 B
通过控制输出的rdata以及对应的rd_valid信号,确定读出成功。在rdata中显示为16进制,16进制的1215为十进制的4629;16进制的3524的为十进制的13604。证明读数据接收正确。1 F; t1 Y5 g, `3 q9 W
; y# z* K$ u5 i$ U4 i9 }
- 板级测试
4 a: a3 K$ z$ z( J& m. O/ j0 U5 W
编写控制器的上游模块(sdr_drive_test_crtl),控制写入和读出。在固定的地址中addr = {2'b01, 13'd128, 9'd20},写入一个固定的数字wdata = 32'h5a5aa5a5,然后读出,进行验证。
2 ~7 W7 U7 r" e/ h- B* y
读者在进行验证时,可以采样其他的地址或者数据进行验证,且可以进行多次尝试,保证设计正确。
0 }* T0 l$ X; d7 G% ^& O2 y0 B
4 |3 f& O1 b+ r: \: j" U该模块采用状态机设计实现。
5 ~7 D- |+ \+ A7 [
$ k5 Q( F/ n, g& |- x
" r' D. F3 L0 ^. p9 s$ W3 T1 A
\! K, T9 h5 A; a( a6 L* ~
( q3 N2 q* F$ Y2 [4 F- r
9 ]. b* [) ?) e" X
设计代码为:
7 q3 ^- A8 \5 H/ q* p
, s# B+ L3 c6 `- H0 D" ~; W
, Y: J2 z f6 o, j: |8 i @9 s5 l9 w' k1 }- b3 m
& u) D# m6 e! t. T% }7 A ^* L
编写测试顶层,模块命名为sdr_drive_test,并且设置为顶层。
9 X( H9 ^0 F1 }
此模块负责例化sdr_drive和sdr_drive_test_ctrl,完成连接功能,以此测试。
6 y# ]; r& F) b" M
% ]7 K: P8 }3 u. \. T! y) x3 A
代码为:
) i% E$ T/ k: M& ~! U
' v9 p. v9 @0 E9 H* v1 ]! O9 W/ O
_6 w0 R7 u' u# p6 L
% o+ }0 {8 u$ p" a7 ]3 s$ g
2 X0 R/ @" B- j: \( w
经过综合分析后,进行分配管脚。在分配管脚后,需要将双功能管脚中的NCEO设置为普通用户IO。如果不设置,将会出现如下错误:
5 @! q0 l8 }: X
7 E9 A8 J+ r5 _; I# V7 g% q
1 h% x! L0 E \6 b# _$ s
# P) m4 }! V; q9 a5 U6 {
! T5 e& X/ b* h
右击器件名称,选择DEVICE。
1 \, I& T" P/ Q
; P/ F/ d# X9 B4 l( D
) z A0 Z$ Y, H7 T. m2 M# w5 [4 ?! d
: Z) A( W& N4 T+ a0 r+ { `
选择device and pin option。
8 O- T; z5 C1 c+ r; Z# j# T
& a7 L3 t3 d( J' g& r' P
4 \8 {, M6 u! k4 C9 J
2 m2 e" m/ r) C& u' e+ c: A
: G* C7 O% c/ n8 f! {
; s m; [; N( v6 D- K! M
* ^9 D9 Q2 C* O; P
选择dual – purpose pins。
" j4 C8 a# d9 M7 p0 a
: k+ Y6 H+ k w+ r9 q5 E
6 K4 X; z8 Z1 w
* P& U, X) Q0 U) |) J: a7 E, c$ Y, W" }
5 M0 ?& N- L/ J5 J* t
+ Q* ]# D9 X; r( K ]7 {6 Y
将nceo设置为 use as regular IO。
! T/ U3 O9 I& [) r' `; i( i
* P1 t. s$ m; I) h
, \% I' K2 k0 H% ^7 i
; ~& v" J% c4 D7 I1 Y3 |
. w4 |( c& U* u3 v' o
点击OK,进行编译即可。
/ i$ e7 W1 }$ r: \$ T; ]- c [: D连接上开发板,启动逻辑分析仪。
5 a% q! r% ?& e) T
2 C7 p8 u! E% [; {3 Y将采样时钟选择为,sys_clk(PLL的c0)。采样深度选择为1K。
% W" U+ y8 v4 h( L! f* d/ t
4 B0 ]! O( W+ Y% z4 f. I
" N7 f2 p! B( O2 V
0 {0 p2 u& U( n% m3 D$ X3 P1 v
% z: T2 f+ }9 t/ _: }% M
添加观测信号如下,将wr_en的上升沿设置为触发条件。
1 R9 M4 a& a! g* |2 D
) a* @2 D1 s7 H1 j9 @; T' ^& K6 o# A
) f: ~: H J, [4 t9 v; r+ }
+ e2 o3 E6 _5 V) B9 w8 Z* ?! w: ]
. j+ q# Y0 i: s* m
经过保存,重新形成配置文件后,进行下板测试。
4 `! k# N* |0 o; W- |5 {7 `
3 J( M+ k3 B, x0 W
5 t, y( C2 J p) U0 h* B4 c下板后,按下复位。等待波形触发。
/ c5 Q( J: g5 p% i' u8 {6 u
" p3 {$ X" z) }+ `
! _4 r% _, `8 X' ~& {
! z' F' c9 f3 p* ]( }
6 X2 w$ K7 F2 Q2 @
通过逻辑分析仪,就可以看出可以正确的写入和读出数据。) N* K6 u4 M/ m4 U2 L( I4 ]
( a6 P- l2 N& z; v: s: D
- h+ F6 }$ k1 B) a, T* V) w! ?
读者也可以进行尝试一次性写入多个数据,然后进行读出,进行验证设计的正确性。
& ^$ F. ^6 ^; `
& \& B4 O; r1 j5 C