ROM的英文全称为Read-Only Memory,即只读存储器。可以从任意地址上读取数据,但是不能写入。那么我们ROM中的数据,就需要我们提前存放进去,在IP核中,我们可以通过.coe文件进行数据存放,文件格式我们可以参考Xilinx官方标准。
! @# d6 R. B6 V' L! C l
数据文件的格式是固定的,我们在填充数据时,需要严格按照官方的格式进行书写。
( x1 z" I7 S& { w& D5 k% y8 H0 f. G; @
7 l/ p6 X( X1 X/ u- Y: U# [; p) F* ] H1 j. t" j4 J5 b
在示例文件中,第一行规定了数据的格式,此处规定的是二进制,那么下面的数据,我们必须用二进制的形式。大家在写的时候,规定什么进制就用什么进制。数据与数据之间用逗号隔开,最后一个数据用分号结尾。
! U) o% \( H3 P" l
了解了数据文件格式之后,接下来我们提前准备一个数据文件,以便于后续我们调用IP核去使用。写数据文件的方法有很多,在此给大家介绍一种:MATLAB。
/ V8 x; Y( J( c7 ^6 |
5 i& C" x! }/ H6 ?我们打开MATLAB之后,首先先选择一下工作路径,以便于我们去找到我们生成的文件以及保存我们的代码。如图:
" k, Q1 z% X, E& n
; K# b+ B- U( [# o+ G2 e
5 U8 r/ o7 W2 \5 v1 K
3 l9 D1 s8 m" w1 e
打开如图所示的图标之后,选择好工程路径。
6 L: t+ {7 f+ }( |) Z: Q$ Q5 g3 a
+ W) h1 y# S9 F0 \. ?选择好之后,我们新建脚本文件,然后写入代码。
$ x6 ]- ]3 L# z- T) V
) m* B" @+ n C; t" ]% \4 M9 l
9 W5 l! @3 X! Z2 V
/ x$ p1 @ M, ?8 s+ f
' D7 v1 V( `1 w4 i5 i) |
写好代码,点击运行,即可生成我们想要的.coe文件。数据文件准备好之后,接下来我们就可以调用IP核了。
9 J! I) J5 v' w) A
1 z& F) z( v( }& o! p' x w/ k! l
首先我们新建一个工程
% T6 M# c) P; J& j3 y* s4 Y
' U' u5 \& h( V2 |. P
e. f0 b8 b$ S1 ~
在第二步选择路径
1 \ m ?) x1 n/ v/ t3 Y
- @- `$ @3 g. }2 \- k" s6 b
9 p3 h2 P+ V: K( x) W9 W
第三步直接跳过,第四步选择我们的芯片,芯片型号为XC7A35TFGG484-2。
! I) |8 W7 E% L) E3 Y; a _ \ {
) ]$ p, ] B1 i( Y
8 l+ E* u" k# c$ W# O! _
选中型号之后,点击Next。
9 m( @& d I: ]' X/ J
工程新建完成之后,开始新建文件。
# A o- d9 ~: F8 l. Z, \) z
! W1 L- k8 T/ r( D, F5 F- ?首先我们先新建IP核,打开IP Catalog,在窗口搜索block
7 ]& l6 g( H( d5 y! R/ z [* ~7 w
- A& j( e! n; y& |8 n) u0 a. _5 f! r6 y0 D6 b4 o
' ?& K3 @! k3 Q' \
- G; ?3 D' E1 {9 |; b; T
找到如图所示选项,然后双击打开。
8 Q$ s) P. t s3 e
- a c h) \! g) z) s1 p7 s5 A5 f+ r0 r8 u2 s/ m' A
我们在框选的选项中,选择Single Port ROM。这个选项中总共有五个选项。第一个为单端口RAM,第二个为伪双端口RAM,第三个为真双端口RAM,第四个为单端口ROM,第五个为真双端口ROM。我们此次使用的是单端口ROM。
2 W1 N! ]4 R4 ^9 h A3 Y' U, g
2 ?1 A* W$ z" W! Q. n
8 H$ ?* }7 h+ i$ r* f
& y l1 w" N! a1 n) f8 F
图中框选出了四处,第一处需要我们修改一下数据的位宽以及深度,位宽我们默认使用8bit,深度为1024。因为我们在前面做了一个数据量为1024的.coe文件,所以这里深度改为1024。第二处为数据输出使能,在此我们选择为Always Enabled。使我们的输出使能一直有效。第三处为输出寄存器,输出会在时钟下输出,导致结果会慢一拍,在此处我们不需要这个选项,因此取消勾选。第四处为ROM复位的设置,如果有需要,可以进行勾选,此处,我没有使用复位信号,大家在使用时自行选择。
" X. |' A$ c: d, K3 d. r& H
. f4 S' L/ D8 Q' O
" J" q! \7 q& w Q; O1 Y5 E
此处我们需要勾选中加载初始化文件的选项,然后点击Browse找到我们提前生成好的数据文件。选择好之后点击OK,生成IP核。
. `" Q# f, E& U1 s/ ]7 A
% N: p* ~4 t3 z
; R# ~0 l6 {3 O! E, T2 x( n
& o: n6 f4 ?4 t9 q) E
直接点击Generate。
% E+ {9 H- m4 J: m
4 X2 k5 j1 h% E; L+ c. I8 FIP核生成好之后,我们新建文件,写一下我们的地址控制模块。代码如下:
" n- ^3 v. M/ _/ k' P
2 q `( q1 I' H) ~% ]+ A( ~' m1 y
, z, M4 c. d9 c5 V* o- E9 g; l" y
然后我们新建顶层文件。写好端口之后,我们将IP核与地址控制模块例化到顶层当中。
! U0 d4 I5 ^% n8 _
+ }7 H8 N4 t" B% e- A2 V( t, l6 Y o. \' J2 l8 m- [
点击Next,选择Create File,新建顶层开始写代码。
* p( v4 J" f2 B% z h
/ e Q, X6 r, h$ d2 {
, ~4 G6 F4 ?- `; `- c. ?( X$ p
7 {2 _2 @) M; h5 {2 u; E7 x' a) W. I, C% f
点击Next,选择Create File,新建顶层开始写代码。
: Q/ z$ d) o* r
- T8 H+ K1 n$ D6 R+ {. O3 I3 W% Y7 U+ ?3 _' `
复制粘贴到顶层当中。地址控制模块也同样进行例化。顶层代码如下:
, {) H" M; b0 a: E% u; E
' T7 x0 [, V1 S1 h4 I! M
! l" f& V4 Q; V2 E+ m( ^
代码写好之后,保存编译,没有错误,那么我们写一下仿真看一下仿真波形。
5 |5 f0 L1 U' v! e
4 d: k# u+ w7 I1 H/ j7 x+ B+ _
9 p2 O. d6 o7 u, ^
选中新建仿真文件,点击Next输入名字。
3 o) m3 b M. i
! X* D+ M* J( n3 Y
! b% y$ O: r1 H
点击OK,开始写代码。仿真代码如下:
6 L3 }( }6 t& d5 q; A# ]
1 i$ R) y4 f; i: |$ M6 _7 L- w7 L7 ]( f p- e- h% l, m- t
代码写好之后,打开仿真。
! C# D; ^, t8 }7 \# U
! Q+ s5 |; B% O# X7 v4 q! @ c2 D: U
波形窗口打开后,点击run all让波形继续运行
# `: l) h. b2 }- N6 l* K. _1 @
# H: e; A; N2 e: k" O
7 x7 \, M" X# w$ Z/ f6 j, Y" Q, c
然后看到如图所示波形。
& b; j* z- s+ W: o; I
$ X# T/ x# u- A2 r. z' l/ F4 f1 \- l4 D0 T, r$ _& g0 l- s" W
* R$ N% x# v" o. m2 f1 N
然后选中输出q,右键选择wavaform style,然后选择analog就可以看到我们的数字信号就变成了模拟信号。
1 f! m6 ~+ u' @4 j
; [2 s- }0 v1 b- f
$ ?# p% a6 _3 ]. g$ i5 p
但是此时波形只有一部分,我们再次点击run all ,然后点击break
: [* d; d e- _8 V r9 b0 Z- v. ~
& R2 g& h7 ^! G/ Q
! S9 y4 X" g q4 {3 L, i
' S: {& D' @5 S. U
就可以看到完整的正弦波。
j: D; T: l2 J3 g( u
' G" K5 ^1 w' b' y6 w
) L9 {: w! U3 Q/ V3 o# x8 W4 V6 Y3 m
我们的数据文件就是做的正弦波,仿真显示正确。