ROM的英文全称为Read-Only Memory,即只读存储器。可以从任意地址上读取数据,但是不能写入。那么我们ROM中的数据,就需要我们提前存放进去,在IP核中,我们可以通过.coe文件进行数据存放,文件格式我们可以参考Xilinx官方标准。
) x4 E2 e2 H' ]9 `
数据文件的格式是固定的,我们在填充数据时,需要严格按照官方的格式进行书写。
9 i1 n3 L' T+ q. c( B( L4 d: y
3 p4 s/ w6 f6 @* W7 R7 \1 P
9 C/ N) `. w" G$ o
在示例文件中,第一行规定了数据的格式,此处规定的是二进制,那么下面的数据,我们必须用二进制的形式。大家在写的时候,规定什么进制就用什么进制。数据与数据之间用逗号隔开,最后一个数据用分号结尾。
. W* h) X( t9 |" y- m/ R
了解了数据文件格式之后,接下来我们提前准备一个数据文件,以便于后续我们调用IP核去使用。写数据文件的方法有很多,在此给大家介绍一种:MATLAB。
/ t" f2 m( O. z$ t0 R H
- T" L7 I% h" y" W* B
我们打开MATLAB之后,首先先选择一下工作路径,以便于我们去找到我们生成的文件以及保存我们的代码。如图:
$ h5 H6 a; F+ {
5 i1 b% D3 V; M
, c0 f' v3 I9 I3 _
' z6 S! z3 I( N- z ^( \
打开如图所示的图标之后,选择好工程路径。
- i, M F% `0 w/ i
7 h6 c, w& A% ]/ o! V! S4 W) @# d$ G
选择好之后,我们新建脚本文件,然后写入代码。
h# U Y% ?& H
/ @, ?5 C3 H, t& L6 J5 g
M7 m* J5 u% l$ X, t
! E( W- N R+ W
9 [! t& S3 T6 F0 Y
写好代码,点击运行,即可生成我们想要的.coe文件。数据文件准备好之后,接下来我们就可以调用IP核了。
* s) E6 W& _/ B" ^5 b0 {
+ Z* [; W$ ]# {& v首先我们新建一个工程
, P9 G H1 i) Y% [
+ ?2 a6 C6 R( b* a1 Y5 X. n' ~
在第二步选择路径
h1 P6 n9 V+ K9 V
/ y; x g1 K4 ^ H
+ l1 ?" N0 c7 h, s2 s6 j8 j c
第三步直接跳过,第四步选择我们的芯片,芯片型号为XC7A35TFGG484-2。
3 w! ^. r' \4 K
) r) [# X" ^* Y4 O m0 t, Z. a
2 |9 y* r6 w, f0 H) Q
选中型号之后,点击Next。
0 F% \- J' V- F5 ]7 I
工程新建完成之后,开始新建文件。
. W% w6 l8 ^, f2 m5 P; ^9 J0 T! A/ u; \
* Q; o' | q2 s7 Q
首先我们先新建IP核,打开IP Catalog,在窗口搜索block
* j8 |4 d7 V# U" M& `5 ?/ ]0 L
. r7 u: t% `: q* I; `; e+ l; \" P6 ^3 {' J/ I( O
+ S0 Q% X) e" E
2 b1 S, S ~' V, b
找到如图所示选项,然后双击打开。
8 o& u0 v M5 Y5 L0 ^7 B. _9 p; [
( l- b& B5 ]; e4 v" _
, P+ }. b; s, t9 U" \8 ~# q
我们在框选的选项中,选择Single Port ROM。这个选项中总共有五个选项。第一个为单端口RAM,第二个为伪双端口RAM,第三个为真双端口RAM,第四个为单端口ROM,第五个为真双端口ROM。我们此次使用的是单端口ROM。
8 _5 l3 z# K! t& J6 [* E5 _
, z& P$ |7 p8 \* W$ s$ G; t6 C
) X5 `- N* W( j1 _- j
! h$ z4 H# J9 k# U, v& p
图中框选出了四处,第一处需要我们修改一下数据的位宽以及深度,位宽我们默认使用8bit,深度为1024。因为我们在前面做了一个数据量为1024的.coe文件,所以这里深度改为1024。第二处为数据输出使能,在此我们选择为Always Enabled。使我们的输出使能一直有效。第三处为输出寄存器,输出会在时钟下输出,导致结果会慢一拍,在此处我们不需要这个选项,因此取消勾选。第四处为ROM复位的设置,如果有需要,可以进行勾选,此处,我没有使用复位信号,大家在使用时自行选择。
! \$ s0 K, ^9 T. K
" ~1 n7 S* B7 P5 l' Y2 |
! ~/ U. Q; ]6 l J9 v, z$ \
此处我们需要勾选中加载初始化文件的选项,然后点击Browse找到我们提前生成好的数据文件。选择好之后点击OK,生成IP核。
6 Q/ A5 _& {# V4 u+ |
' T( X; Z c5 O! G% w$ F' ~
& M: D# M5 ^2 N; x& C6 D
% N) m- F; _" K% u- E5 \3 W$ A
直接点击Generate。
8 n3 K* y* K' g" R( F7 c
) t/ _: O% _" F0 u- JIP核生成好之后,我们新建文件,写一下我们的地址控制模块。代码如下:
' f8 w7 b& c( T& C% ]
7 E( C0 j) B: z! H
1 k/ i2 k* X( P. ?$ F1 \4 e1 Z
然后我们新建顶层文件。写好端口之后,我们将IP核与地址控制模块例化到顶层当中。
2 k/ T; V& s( X1 N4 d
3 L# a1 z4 w/ R; ?+ x: C: \
5 A, ]2 P/ \0 c1 j
点击Next,选择Create File,新建顶层开始写代码。
1 [) o3 W% s5 N& ]
3 n. D2 |1 A% h' [# c8 \9 w
0 @. n" z( S- `/ ~. N
8 s& }: L+ ]4 Q
2 t7 u7 J8 I) P( H! P$ j
点击Next,选择Create File,新建顶层开始写代码。
' H4 Z; n2 {; e8 C! g7 p4 Y8 t
; L0 E: ^7 l! X( Z& S; x5 v
$ m; k% z) _% x$ G+ y
复制粘贴到顶层当中。地址控制模块也同样进行例化。顶层代码如下:
# Y- u9 i3 ^, f+ c2 M8 @% ^. F# ~
& n: [. b0 Y4 p- q0 a7 q. l
% `# m1 j3 D. \( k8 ~" v+ _6 b
代码写好之后,保存编译,没有错误,那么我们写一下仿真看一下仿真波形。
( J: G8 B8 ^3 e: r; C) W
/ H5 j" e" @6 i/ _
7 M% A, K* a" P8 x; q
选中新建仿真文件,点击Next输入名字。
% P/ k: M1 T8 Q& \( ~+ z- A( k
- O9 N1 g# Q/ P0 R! z* [- H! U7 } p2 M: b3 `0 X' _7 T
点击OK,开始写代码。仿真代码如下:
3 W# W/ F; n0 ~
* u& M: L; c' [: ^1 I* h) E
6 v, ?) a1 {3 M
代码写好之后,打开仿真。
1 x2 v* d, ]6 G" j
) B7 a e8 m" q- Q
1 D9 Z/ e2 X8 u% w* T9 Y. d
波形窗口打开后,点击run all让波形继续运行
4 l' t- x+ i1 w4 ]% g
- }' d- I& D# K$ p( R0 r) h4 h5 [
然后看到如图所示波形。
/ ?+ A4 w* Z8 m; V3 ~
m6 g5 a, z$ T8 D) l! |) ?& S4 j! W- V# H' N2 C
" \ k. }; t0 k3 p
然后选中输出q,右键选择wavaform style,然后选择analog就可以看到我们的数字信号就变成了模拟信号。
1 K7 k* b$ ]8 e( q% u. l. N3 b
$ I1 Q' i! p. K4 j- V( I
$ B. L: k0 N9 P" ^8 f' T
但是此时波形只有一部分,我们再次点击run all ,然后点击break
, G; J1 t& H( I$ O m$ G+ x
0 l% n- N" A2 k1 D r: |( d
0 f- N2 E1 i1 \% ~( h% p t7 q& I/ E* i8 \! k9 X3 V- N
就可以看到完整的正弦波。
, Q- f Q1 y& h0 M% c. W1 V s
, \, s9 c- h, z3 \0 j2 P7 m4 K2 T9 k3 [
我们的数据文件就是做的正弦波,仿真显示正确。