你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32MP1嵌入式Linux驱动开发指南V1.7-IP核之RAM实验

[复制链接]
STMCU小助手 发布时间:2022-9-28 18:28
IP核之RAM实验
5 u" q+ ^3 ^. I% M5 p: IRAM的英文全称是Random Access Memory,即随机存取存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度是由时钟频率决定的。RAM主要用来存放程序及程序执行过程中产生的中间数据、运算结果等。本章我们将对Vivado软件生成的RAM IP核进行读写测试,并向大家介绍Xilinx RAM IP核的使用方法。
: e+ b5 W$ h' z9 M4 x# g4 `  s9 r/ X; b
14.1 RAM IP核简介( j3 |" \1 n; v1 E
Xilinx 7系列器件具有嵌入式存储器结构,满足了设计对片上存储器的需求。嵌入式存储器结构由一列列BRAM(块RAM)存储器模块组成,通过对这些BRAM存储器模块进行配置,可以实现各种存储器的功能,例如:RAM、移位寄存器、ROM以及FIFO缓冲器。
& ]. J6 h( U6 }5 [! PVivado软件自带了BMG IP核(Block Memory Generator,块RAM生成器),可以配置成RAM或者ROM。这两者的区别是RAM是一种随机存取存储器,不仅仅可以存储数据,同时支持对存储的数据进行修改;而ROM是一种只读存储器,也就是说,在正常工作时只能读出数据,而不能写入数据。需要注意的是,配置成RAM或者ROM使用的资源都是FPGA内部的BRAM,只不过配置成ROM时只用到了嵌入式BRAM的读数据端口。本章我们主要介绍通过BRAM IP核配置成RAM的使用方法。
& B  a9 F( w+ I: I# qXilinx 7系列器件内部的BRAM全部是真双端口RAM(True Dual-Port ram,TDP),这两个端口都可以独立地对BRAM进行读/写。但也可以被配置成伪双端口RAM(Simple Dual-Port ram,SDP)(有两个端口,但是其中一个只能读,另一个只能写)或单端口RAM(只有一个端口,读/写只能通过这一个端口来进行)。单端口RAM只有一组数据总线、地址总线、时钟信号以及其他控制信号,而双端口RAM具有两组数据总线、地址总线、时钟信号以及其他控制信号。有关BRAM的更详细的介绍,请读者参阅Xilinx官方的手册文档“UG473,7 Series FPGAs Memory Resources User Guide”。
( q. H8 v8 x9 k3 w1 Q% ^+ W. \单端口RAM类型和双端口RAM类型在操作上都是一样的,我们只要学会了单端口RAM的使用,那么学习双端口RAM的读写操作也是非常容易的。本章我们以配置成单端口RAM为例进行讲解。
; G8 d) P: g* R0 ^BMG IP核配置成单端口RAM的框图如下图所示。
6 K; n& i& w* o1 d' Y1 X/ h/ q7 e3 ^4 h" e/ D5 h4 [
8b3c028023b84ce38c7296da8baa126b.png " j3 t. Y2 N  P% s7 L' ~

1 R) \! q) u/ P) ^* M- z图 7.5.13.1 单端口RAM框图! [) o7 b" _/ ?* ^+ ]
各个端口的功能描述如下:+ _" F5 Q; i: u) i- w  ^) H
DINA:RAM端口A写数据信号。: P6 p* ]- L  H* C
ADDRA:RAM端口A读写地址信号,对于单端口RAM来说,读地址和写地址共用同该地址线。7 B$ M, p/ y+ g* O. g- S* |$ G
WEA:RAM端口A写使能信号,高电平表示向RAM中写入数据,低电平表示从RAM中读出数据。
8 U# }7 C% Z3 m- r' C) D2 P$ }ENA:端口A的使能信号,高电平表示使能端口A,低电平表示端口A被禁止,禁止后端口A上的读写操作都会变成无效。另外ENA信号是可选的,当取消该使能信号后,RAM会一直处于有效状态。
2 l( G: N$ G3 y, X" vRSTA:RAM端口A复位信号,可配置成高电平或者低电平复位,该复位信号是一个可选信号。; c8 R1 Q% b, q( c, L
REGCEA:RAM端口A输出寄存器使能信号,当REGCEA为高电平时,DOUTA保持最后一次输出的数据,REGCEA同样是一个可选信号。
" \; n4 h! g2 r) R$ y" ]7 M/ u9 NCLKA:RAM端口A的时钟信号。
* ~% Q! @1 o# {7 J6 ^& Z* E" ]" qDOUTA:RAM端口A读出的数据。8 Q8 m" r5 `: h/ K9 O6 o
14.2 实验任务
& T4 r1 T. E/ d3 d& K本节实验任务是使用Xilinx BMG IP核,配置成一个单端口的RAM,然后对RAM进行读写操作,通过在Vivado自带的仿真器中观察波形是否正确,最后将设计下载到领航者Zynq开发板中,并使用ILA对其进行在线调试观察。
. o$ U  s: q3 \6 i7 R  W$ r14.3 硬件设计/ a: R; H- {) r; l0 t( u. W
本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设,各端口信号的管脚分配如下表所示:* c; y; {8 B! ]
表 14.3.1 IP核之RAM实验管脚分配  e5 x# ^- n8 W/ A
信号名 方向 管脚 端口说明 电平标准7 X7 Q# K- y! o/ h" Y- V: E
sys_clk input U18 系统时钟,50Mhz LVCMOS33* R+ I9 L7 j: Z3 S
sys_rst_n input N16 系统复位,低电平有效,位于底板上 LVCMOS33
3 a$ v0 }5 M7 g+ y对应的XDC约束语句如下所示:0 ~2 X% a  s3 J1 M% O) C1 Z8 d
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
% \1 o$ A- @* n4 jset_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]6 e! W6 _& z3 v9 J

2 n9 t7 J: d" c& X' _' C14.4 程序设计
, H! B+ u. h% z首先在Vivado软件中创建一个名为ip_ram的工程,工程创建完成后,在Vivado软件的左侧“Flow Navigator”栏中单击“IP Catalog”,如下图所示。6 J4 G2 W# `' a9 v8 n4 t
7 q9 g. S5 K' d" j3 q0 s! ?- S; A
b51680fe952d4f7982318f18cc3de527.png
# P4 M; ]6 t+ h6 Y5 t% r% @1 m# M& }+ v) o1 F
图 7.5.13.1 点击“IP Catalog”2 K8 j. j- o1 r, c1 S% x
在“IP Catalog”窗口的搜索框中输入“Block Memory”,出现唯一匹配的“Block Memory Generator”,如下图所示(图中出现的两个IP核为同一个BMG IP核)。/ Q, t( U4 U( S# O- F( e% F* k
3 w  u# d% _! s
9c2a77bf771d462ea50b83317e49a4cf.png 0 e- e* y" \' |3 V! S
# n! |* [& ^0 d' H
图 7.5.13.2 搜索框中输入“Block Memory”4 B; x$ C$ g4 x
双击“Block Memory Generator”后弹出IP核的配置界面,接下来对BMG IP核进行配置,“Basic”选项页配置界面如下图所示。
+ @( Z, C) Q2 G4 k
' X4 i3 t' Z. z; S2 p% y6 c1 g% G 1831e95fe3a14d40997a4652f460086a.png
' E+ m6 ^0 H7 `  e) X5 j1 q! i; k; O+ j- Y' L
图 7.5.13.3 “Basic”选项页配置4 E+ Z3 a) L# D
Component Name:设置该IP核的名称,这里保持默认即可。
& X( g9 O; w2 n+ y$ kInterface Type:RAM接口总线。这里保持默认,选择Native接口类型(标准RAM接口总线);
) h' ^' ~+ \3 eMemory Type:存储器类型。可配置成Single Port RAM(单端口RAM)、Simple Dual Port RAM(伪双端口RAM)、True Dual Port RAM(真双端口RAM)、Single Port ROM(单端口ROM)和Dual Port ROM(双端口ROM),这里选择Single Port RAM,即配置成单端口RAM。% h' d( i- X' R$ ]4 Y
ECC Options:Error Correction Capability,纠错能力选项,单端口RAM不支持ECC。
& E' C  v  Y0 CWrite Enable:字节写使能选项,勾中后可以单独将数据的某个字节写入RAM中,这里不使能。
& l' u$ C! I3 S, x. O6 C! x* xAlgorithm Options:算法选项。可选择Minimum Area(最小面积)、Low Power(低功耗)和Fixed Primitives(固定的原语),这里选择默认的Minimum Area。
2 G+ ^" P$ [& |. h" W8 x接下来切换至“Port A”选项页,设置端口A的参数,该页面配置如下:5 X3 |( x4 j6 {. b6 K4 m
9 ~+ i$ f* M7 A" ^# J. j6 D
0b7c3926b9cf43dd8e24360393043f77.png ; g" ?* V; Z; f( [5 P, n# E

; t+ ?& Y. [5 g& m2 _4 I图 7.5.13.4 “Port A Options”选项页配置: h8 ^& H+ Y* I( I; Q2 p5 u
Write Width:端口A写数据位宽,单位Bit,这里设置成8。
2 _9 u+ f$ s+ {' f0 E& vRead Width:端口A读数据位宽,一般和写数据位宽保持一致,设置成8。
4 N) r3 H% b/ m1 K, _; h5 G6 gWrite Depth:写深度,这里设置成32,即RAM所能访问的地址范围为0-31。
' b; w' ^& D5 Z: \/ f; oRead Depth:读深度,默认和写深度保持一致。
( a" B9 ^. K7 H8 y& q1 pOperating Mode:RAM读写操作模式。共分为三种模式,分别是Write First(写优先模式)、Read First(读优先模式)和No Change(不变模式)。写优先模式指数据先写入RAM中,然后在下一个时钟输出该数据;读优先模式指数据先写入RAM中,同时输出RAM中同地址的上一次数据;不变模式指读写分开操作,不能同时进行读写,这里选择No Change模式。# O6 x# r9 }: @6 T' u; M- P) b
Enable Port Type:使能端口类型。Use ENA pin(添加使能端口A信号);Always Enabled(取消使能信号,端口A一直处于使能状态),这里选择默认的Use ENA pin。" a, f# Y' i& U! a+ J% v
Port A Optional Output Register:端口A输出寄存器选项。其中“Primitives Output Register”默认是选中状态,作用是打开BRAM内部位于输出数据总线之后的输出流水线寄存器,虽然在一般设计中为了改善时序性能会保持此选项的默认勾选状态,但是这会使得BRAM输出的数据延迟一拍,这不利于我们在Vivado的ILA调试窗口中直观清晰地观察信号;而且在本实验中我们仅仅是把BRAM的数据输出总线连接到了ILA的探针端口上来进行观察,除此之外数据输出总线没有别的负载,不会带来难以满足的时序路径,因此这里取消勾选。3 a: T. j! ^( V; w9 |
Port A Output Reset Options:RAM复位信号选项,这里不添加复位信号,保持默认即可。
; R* T& i  e$ T& m* X另外,需要注意的是,下面的“Primitives Output Register”默认是选中状态的,此选项的作用是打开块RAM内部的位于输出数据总线之后的输出流水线寄存器,虽然在一般设计中为了改善时序性能会保持此选项的默认勾选状态,但是这会使得块RAM输出的数据延迟一拍,这不利于我们在Vivado的ILA调试窗口中直观清晰地观察信号;而且在本实验中我们仅仅是把块RAM的数据输出总线连接到了ILA的探针端口上来进行观察,除此之外数据输出总线没有别的负载,不会带来难以满足的时序路径。' `$ F" U' y' U+ p; \0 A
接下来的“Other Options”选项页用于设置RAM的初始值等,本次实验不需要设置,直接保持默认即可。* Y! z2 D4 L+ b, E
最后一个是“Summary”选项页,该页面显示了存储器的类型,消耗的BRAM资源等,我们直接点击“OK”按钮完成BMG IP核的配置,如下图所示:6 J# H& o$ f6 Y  G2 C) H0 N

. I/ V! ]  K  N7 o) ?- |/ X 9e6564b015af464e8be028a6f5f20c1c.png ' M1 w) u7 \; W+ Q# |

# o/ U) h- M) _7 @" L6 J% s图 7.5.13.5 “Summary”选项页) u4 u+ _, L) H5 f5 W+ A& `8 q* [
接下来会弹出询问是否在工程目录下创建存放IP核的文件,我们点击“OK”按钮即可。
$ T% o" b# U( e9 U  L2 m7 [4 l紧接着会弹出“Genarate Output Products”窗口,我们直接点击“Generate”,如下图所示。
/ x- e! Z" N# b0 v6 b1 Y1 D! w3 N
/ v2 `- }0 Y% N0 K8 A% I# | 60edd96a90c540feaacee61a48044a13.png 8 _& K: ?, x' v2 a+ @

, T; g( b, J* L. D5 z, R! A. K3 \图 7.5.13.6 “Genarate Output Products”窗口
1 }* \4 d2 H, b  ^: y/ R4 R+ i0 |之后我们就可以在“Design Run”窗口的“Out-of-Context Module Runs”一栏中出现了该IP核对应的run“blk_mem_gen_0_synth_1”,其综合过程独立于顶层设计的综合,所以在我们可以看到其正在综合,如下图所示。
! ^% p; N& j$ l3 ^% W6 U
: i4 [3 w6 z: ^ bcb3fc97671c4e47a879d55fa4636f0e.png ' N, ~( D4 w) q
+ i1 v) I, O& C+ R. }4 ~- i0 Y
图 7.5.13.7 “blk_mem_gen_0_synth_1”run' u8 M! ^4 o, y; |
在其Out-of-Context综合的过程中,我们就可以进行RTL编码了。首先打开IP核的例化模板,在“Source”窗口中的“IP Sources”选项卡中,依次用鼠标单击展开“IP”-“blk_mem_gen_0”-“Instantitation Template”,我们可以看到“blk_mem_gen_0.veo”文件,它是由IP核自动生成的只读的verilog例化模板文件,双击就可以打开它,如下图所示。
* Z6 w* S) `( Q
. I- U( q4 [# E) g0 s# [6 ? afa4baf10c014462accf810c656a8d97.png . R8 \- F1 }) W
, f0 b  f+ o! [& W# X
图 7.5.13.8 “blk_mem_gen_0.veo”文件
" Z# t& e. v$ `2 H$ a( c# [接下来我们创建一个新的设计文件,命名为ram_rw.v,代码如下:
' @6 D2 ^# H# ~& T( X5 c4 r8 l
3 A' @: Q: i4 `! T" e. M6 i9 c6 @
  1. 1  module ram_rw(
    % D2 J0 [  @. B% I# J
  2. 2      input               clk        ,  //时钟信号
    ! L+ S8 R. d- g
  3. 3      input               rst_n      ,  //复位信号,低电平有效
    " L0 l* z. |# j+ {5 X
  4. 4      " w% A5 q' J4 d4 p! q
  5. 5      output              ram_en     ,  //ram使能信号( C7 F" Y3 }9 a4 f; k
  6. 6      output              ram_wea    ,  //ram读写选择
    # g- J1 a0 f1 p. d; J  d
  7. 7      output  reg  [4:0]  ram_addr   ,  //ram读写地址( ]" Z8 n" J0 C; {$ E
  8. 8      output  reg  [7:0]  ram_wr_data,  //ram写数据
    * h% a6 h$ H! w, K" \- N6 F
  9. 9      input        [7:0]  ram_rd_data   //ram读数据        , D1 a' q3 I, A/ f
  10. 10     );
    ! B" G3 M: F& P) f% H& [2 C# Q1 {* x
  11. 11 " \9 ^2 p% V$ ^; z- `6 C
  12. 12 //reg define1 a! b& t* v2 j5 }* x$ {
  13. 13 reg    [5:0]  rw_cnt ;                //读写控制计数器& t0 @0 K, F* p& V' K+ Q3 ^
  14. 14 + b  v+ Q! p/ O9 D. @
  15. 15 //*****************************************************5 z' x3 \0 ?0 Z0 ?: W
  16. 16 //**                    main code
    + K% A! y4 i1 F& A/ x! q4 k) t1 w
  17. 17 //*****************************************************& [% T+ v6 L( a, u
  18. 18 + E- P1 w/ Y" e% D: y
  19. 19 //控制RAM使能信号6 I# S, M2 g4 V4 S5 n4 _
  20. 20 assign ram_en = rst_n;
    ! w& o1 g  f! d% e$ i) _+ Y
  21. 21 //rw_cnt计数范围在0~31,写入数据;32~63时,读出数据
    ! H" r  T3 }/ e& P" Y0 K% I9 L
  22. 22 assign ram_wea = (rw_cnt <= 6'd31 && ram_en == 1'b1) ? 1'b1 : 1'b0;
    ( V6 P& F9 s& z" T
  23. 23
    " k) O4 R; \- p: Q
  24. 24 //读写控制计数器,计数器范围0~638 f( Q4 K1 \* a7 Q. ]$ E: w' i
  25. 25 always @(posedge clk or negedge rst_n) begin
    ' m2 m4 V! R1 L! v3 j3 Y
  26. 26     if(rst_n == 1'b0)
    # ]$ T  l, a! r2 @( j, V
  27. 27         rw_cnt <= 1'b0;    $ ^1 i3 l- u8 g9 I
  28. 28     else if(rw_cnt == 6'd63)
    ) ?( I$ Z" i) I; q
  29. 29         rw_cnt <= 1'b0;
    - [* I0 y- N' B
  30. 30     else
    8 V3 G7 V- k$ M, O! o
  31. 31         rw_cnt <= rw_cnt + 1'b1;   
    ; _; a3 T; ~# y1 B; M0 X, b
  32. 32 end  
    8 Z* m8 w& [7 |& y3 Y. ^" \4 j" M
  33. 33 , f7 x/ I) z, x7 c
  34. 34 //产生RAM写数据" V9 s8 R) e4 J/ l9 @0 u
  35. 35 always @(posedge clk or negedge rst_n) begin( l2 O- s( p* y( `5 ^: ?
  36. 36     if(rst_n == 1'b0)
    8 h1 ]9 U- [. L6 J
  37. 37         ram_wr_data <= 1'b0;  ; f, ~3 `8 Z9 n/ Y. l3 `
  38. 38     else if(rw_cnt <= 6'd31)  //在计数器的0-31范围内,RAM写地址累加) P( K. K5 j0 S
  39. 39         ram_wr_data <= ram_wr_data + 1'b1;
    7 X3 y+ p1 m# x+ Q1 {
  40. 40     else
    # n; s; \% U3 G' Y6 N0 H
  41. 41         ram_wr_data <= 1'b0 ;   / C: ?" C; r) h3 K( D3 B1 c+ q6 Q
  42. 42 end  9 M/ i8 m' ]1 x% @7 y  e( I" k. e7 h8 ~
  43. 43
    % y* K" e  L4 O0 J
  44. 44 //读写地址信号 范围:0~31
    - Q& t& ]9 V! w! x6 _" g% J
  45. 45 always @(posedge clk or negedge rst_n) begin
    ) d6 h. l" j7 O- p2 _9 {
  46. 46     if(rst_n == 1'b0)
    * n8 f0 a" T+ G
  47. 47         ram_addr <= 1'b0;
    & X, D, w- w' \& F1 s! B
  48. 48     else if(ram_addr == 5'd31)7 x/ |3 g6 C' t; v0 W
  49. 49         ram_addr <= 1'b0;) a) p" ]0 V) L. q! I, j, a( }# X  [
  50. 50     else   
    8 x/ k& g# O; F0 |4 w
  51. 51         ram_addr <= ram_addr + 1'b1;
    ; {8 u5 I4 s& r3 o' }; m. a6 v
  52. 52 end
    2 j, S8 {$ A& x: x
  53. 53 - j2 _8 e8 s* F. X
  54. 63 endmodule
复制代码
% k7 B: `5 x% R$ Q
模块中定义了一个读写控制计数器(rw_cnt),当计数范围在031之间时,向ram中写入数据;当计数范围在3263之间时,从ram中读出数据。
! d8 W9 c/ O7 E, [* c接下来我们设计一个verilog文件来实例化创建的RAM IP核以及ram_rw模块,文件名为ip_ram.v, 编写的verilog代码如下。# l/ c" ?  ~0 Q& D% O
' Z2 K/ n) f. i! k8 P
  1. 1  module ip_ram(- V4 P+ N" f$ s, l6 H. z) Z
  2. 2      input         sys_clk ,  //系统时钟
    ( E* W! J, H' w* ~+ G- \
  3. 3      input         sys_rst_n  //系统复位,低电平有效$ v0 J/ R$ N* T% E
  4. 4      );
    : ^& q0 l2 ?8 V5 R, {' T% ?! a. l1 O" ~
  5. 5  8 f* F6 R) V3 ~1 Y1 J
  6. 6  //wire define
    ( X  P, T* O1 U1 ], r6 }
  7. 7  wire             ram_en      ;  //RAM使能   
    + `3 x0 Y, h# I" M8 m. j
  8. 8  wire             ram_wea     ;  //ram读写使能信号,高电平写入,低电平读出 ! }0 m6 d. V) `/ \* ]
  9. 9  wire    [4:0]    ram_addr    ;  //ram读写地址 4 ^; s+ W- E8 q  p% v7 @
  10. 10 wire    [7:0]    ram_wr_data ;  //ram写数据  
    , K- g: r& e, B; O* e
  11. 11 wire    [7:0]    ram_rd_data ;  //ram读数据  - M! A+ i8 Y8 W' Y! O6 r2 L
  12. 12 3 j3 n: W! B5 l- Y4 A
  13. 13 //*****************************************************
    6 u; U" Y5 t: O! M
  14. 14 //**                    main code
    ! ?( ^) ~1 X" I4 ?* D9 R6 b
  15. 15 //*****************************************************; g" o1 d6 R! _; L* m4 h. C3 i
  16. 16 0 Q2 h& T" e  @) K  V
  17. 17 //ram读写模块
    4 y# ]! {( Z- j, d" B1 x  _/ _+ Q
  18. 18 ram_rw  u_ram_rw(
    % {1 ?) l$ h2 k( z. U" z
  19. 19     .clk            (sys_clk     ),9 G, E( S2 w* U( T- v
  20. 20     .rst_n          (sys_rst_n   ),
    6 }! ~. [3 N/ M; B; Z9 V$ p' a0 G
  21. 21  //RAM
    1 j9 R! `) \# t" O/ X2 y1 e# l+ B. y
  22. 22  .ram_en         (ram_en      ),
    + \# g- h  z: Q! K% [* O
  23. 23     .ram_wea        (ram_wea     ),
    4 z  z: ^6 Z" J- ^$ H1 u
  24. 24     .ram_addr       (ram_addr    ),
    0 U$ \* F8 ^/ }  D7 n' b5 i3 u
  25. 25     .ram_wr_data    (ram_wr_data ),2 x& Q! R- K! O; ^
  26. 26     .ram_rd_data    (ram_rd_data ). ~  M  w3 M" O7 F; a7 O
  27. 27     );
    - [6 g% E; _# x/ L# h  [
  28. 28
    ( d* X- Z( ^/ @; R# G2 h) D1 c; \
  29. 29 //ram ip核
    : R1 e  h4 p* Q& l0 W; [
  30. 30 blk_mem_gen_0  blk_mem_gen_0 (  D% Y, Q1 H0 U: p) M/ D
  31. 31  .clka  (sys_clk      ),  // input wire clka
    6 M! G9 l9 [! a; Z6 u/ x% J
  32. 32  .ena   (ram_en       ),  // input wire ena    I2 c% l: A4 r  C4 h
  33. 33  .wea   (ram_wea      ),  // input wire [0 : 0] wea
    + U7 M+ x( D/ I
  34. 34  .addra (ram_addr     ),  // input wire [4 : 0] addra7 o5 b( d% J  l% u8 u- G
  35. 35  .dina  (ram_wr_data  ),  // input wire [7 : 0] dina5 O4 Z! P2 _: {+ O  P& m
  36. 36  .douta (ram_rd_data  )  // output wire [7 : 0] douta
    ! [, o- \0 e8 D& t4 V. U1 N
  37. 37 );0 N+ H# [( g  \+ a
  38. 38
    8 m0 b/ E) ~4 l- g2 L/ D+ f
  39. 39 endmodule" N3 c6 M0 l- _, U# B- u+ W
复制代码
  u0 Y2 |/ s# o+ R2 h4 K
程序中例化了ram_rw模块和ram IP核blk_mem_gen_0,其中ram_rw模块负责产生对ram IP核读/写所需的所有数据、地址以和读写使能信号,同时从ram IP读出的数据也连接至ram_rw模块。
% ]+ Q; I5 [7 ?. @2 \) W& E% z! k7 R接下来对RAM IP核进行仿真,来验证对RAM的读写操作是否正确。tb_ip_ram仿真文件源代码如下:9 \5 W+ |9 E5 o7 a3 [4 p$ X
! D/ @2 ^5 T; M0 n/ Z# T
  1. 1  `timescale 1ns / 1ps
    7 T, ~8 E+ A" Z- W& |+ T* r/ h/ m
  2. 2  . Q5 g8 n& s9 i. k: P
  3. 3  module tb_ip_ram();- L- }# b% R" b( m$ m! p3 P
  4. 4  
    $ g, d4 u) n, U& J) {$ q8 O
  5. 5  reg     sys_clk;& H' _, X6 j$ n8 x* D+ _
  6. 6  reg     sys_rst_n;      ; V: g8 J+ [3 z  G7 b$ O) C% y( ~+ f
  7. 7  1 b- O/ h3 n* T3 Q; o3 u4 {
  8. 8  always #10 sys_clk = ~sys_clk;
    7 f9 C6 [. H+ t! ^* i( v9 ]
  9. 9  1 D5 w$ L+ M# X  g' }: S9 o
  10. 10 initial begin! w5 N; X0 j! m+ b, D( N; x
  11. 11     sys_clk = 1'b0;
    2 P; y8 g* ^/ `7 o; {
  12. 12     sys_rst_n = 1'b0;) e, Q- ^8 S  T) x% C/ A" s- l
  13. 13     #200- A! ?$ E- J" u2 ?  j
  14. 14     sys_rst_n = 1'b1;- y$ ]: m) Y' Z
  15. 15 end
    . u: n& u( g, A3 |7 A
  16. 16
    6 ]: N& K/ t/ q$ l3 \" R
  17. 17 ip_ram u_ip_ram(( @% |( X$ k3 p8 G; i
  18. 18     .sys_clk          (sys_clk        ),
    ! ]3 }% {* i& N, c/ a
  19. 19     .sys_rst_n        (sys_rst_n      )
    # k8 g) U, a/ r3 P. f6 X
  20. 20     );
    0 C+ _1 T  J* Q3 w3 m2 ^
  21. 21   p+ z' Z1 o3 x1 P1 L, ]; b
  22. 22 endmodule
复制代码

& x  o1 A8 o! X4 M- b+ B) ?接下来就可以开始仿真了,仿真过程这里不再赘述,仿真波形图如下图所示。
  J6 v+ O$ Z7 r% H9 W- l5 A( q1 c' j7 l- q2 R
4db20b931d2c4b808a2a1053ba76d195.png - [2 B+ l5 S& W* f+ z: g: ]$ r
; Q- y: x) S5 j9 p5 d( `
图 7.5.13.9 RAM写操作波形图
8 i/ ~  d  N% M: k, H, d图 7.5.13.9为RAM的写操作仿真波形图,由上图可知,ram_wea信号拉高,说明此时是对ram进行写操作。ram_wea信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1,我们总共向ram中写入32个数据。
8 M/ Z1 x# N4 S) E* W' pRAM读操作仿真波形图如下图所示:1 f6 Z; P2 }0 h3 F
  \$ g  I. U3 V* P
195b7746c75345a48302e77bdfdf8167.png   [* Y3 U. D! X& v$ }2 ]

& S" X3 [7 Y7 N' @1 \' h- |9 H! n图 7.5.13.10 RAM读操作波形图* L: K/ r+ Q5 h# `% y$ u  l
由上图可知,ram_wea信号拉低,说明此时是对ram进行读操作。ram_wea信号拉低之后,ram_addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据ram_rd_data在延时一个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的, 也就是说,我们创建的RAM IP核从仿真结果上来看是正确的。
4 o5 n5 H7 F# `3 I接下来添加ILA IP核,将ram_en、ram_wea、ram_addr、ram_wr_data和ram_rd_data信号添加至观察列表中,添加ILA IP核的方法这里不再赘述。
0 E( C) e- ?' n' n$ n5 A最后为工程添加IO管脚约束,对应的XDC约束语句如下所示:) n$ d, u2 L( C: Y  o! a
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
' @. G. Y8 A, G6 Uset_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]* F$ p2 W4 Q  B$ L) J
14.5 下载验证
. z0 g7 A4 b! g- b) Z5 d8 M- [- Q编译工程并生成比特流.bit文件。将下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,连接电源线,并打开开发板的电源开关。6 S- D. s% F7 L9 z' J
点击Vivado左侧“Flow Navigator”窗口最下面的“Open Hardware Manager”,此时Vivado软件识别到下载器,点击“Hardware”窗口中“Progam Device”下载程序,在弹出的界面中选择“Program”下载程序。
. c8 N. `8 I8 L0 A) @( t" Y1 SRAM写操作在ILA中观察的波形如下图所示:
  }: T& p) U9 [. n. A- E8 }4 }' L' `# d* W9 l9 C
8affbe9fbb804659aaa571c29baf6385.png , O  E, V& F6 A7 a
- [9 r2 s7 s) ~, y: W9 g
图 7.5.13.1 RAM写操作ILA波形图
4 B. H  O- V+ @* {: j9 o- zram_wea信号拉高之后,地址和数据都是从0开始累加,也就说当ram地址为0时,写入的数据也是0;当ram地址为1时,写入的数据也是1。我们可以发现,上图中的数据变化和在Vivado仿真的波形是一致的。' N+ P7 |/ _, z+ ~
RAM读操作在ILA中观察的波形如下图所示:
8 ~! f% l6 v- R& z" \( l2 b; J6 U5 C8 j4 K5 \( b
4738ea30947f4b76b6ce15d396b2fe47.png ( R8 M) R1 a* y4 w

$ c2 W  U9 U( p4 M图 7.5.13.2 RAM读操作ILA波形图
/ K& D& V: l! Z& X+ fram_wea(读使能)信号拉低之后,ram_addr从0开始增加,也就是说从ram的地址0开始读数据;ram中读出的数据ram_rd_data在延时一个时钟周期之后,开始输出数据,输出的数据为0,1,2……,和我们写入的值是相等的。我们可以发现,上图中的数据变化同样和Vivado仿真的波形是一致的。本次实验的IP核之RAM读写实验验证成功。
+ O1 y* {( l- L# \: B$ G————————————————! w# r; r1 i2 J; }0 Q) i5 Y/ w
版权声明:正点原子
( x. Q3 a" H4 d, w; K( ^
) s. g, A, r  y) M/ o; j5 r  f1 }; }7 V9 M/ [+ Q

; Y% j+ c; |8 V' f
赞 收藏 评论0 发布时间:2022-9-28 18:28

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版