ROM的英文全称为Read-Only Memory,即只读存储器。可以从任意地址上读取数据,但是不能写入。那么我们ROM中的数据,就需要我们提前存放进去,在IP核中,我们可以通过.coe文件进行数据存放,文件格式我们可以参考Xilinx官方标准。
; x; {+ a/ Z- [7 n& Z9 \
数据文件的格式是固定的,我们在填充数据时,需要严格按照官方的格式进行书写。
: D+ V# h: }- O$ Y7 G! X- _+ J
7 B9 M. G& r5 Z8 H
2 o( w! f& I5 P$ n+ h! n9 p
在示例文件中,第一行规定了数据的格式,此处规定的是二进制,那么下面的数据,我们必须用二进制的形式。大家在写的时候,规定什么进制就用什么进制。数据与数据之间用逗号隔开,最后一个数据用分号结尾。
, B [2 O4 T/ a8 [4 V) B u) l7 i: x
了解了数据文件格式之后,接下来我们提前准备一个数据文件,以便于后续我们调用IP核去使用。写数据文件的方法有很多,在此给大家介绍一种:MATLAB。
9 ^2 t8 r9 L: }9 t
1 M/ K$ W0 a% q7 X7 G y. D B我们打开MATLAB之后,首先先选择一下工作路径,以便于我们去找到我们生成的文件以及保存我们的代码。如图:
! ~6 q6 ^) d" ?% C- n
* Z2 A ~2 x5 O
) I7 C! R5 t- k( Y
1 \$ i6 j# O% S$ u
打开如图所示的图标之后,选择好工程路径。
8 b/ ?- l- p& P6 `. s
% S; ~4 s1 e h
选择好之后,我们新建脚本文件,然后写入代码。
# M$ b% N; t) Y7 \- z, d" ?
" \" c! J6 S" t; u% E
8 s$ p% M5 ]; M8 @
" s5 A, e1 r3 I) b5 `! M
7 j% J) g% b6 k$ i
写好代码,点击运行,即可生成我们想要的.coe文件。数据文件准备好之后,接下来我们就可以调用IP核了。
. O8 n6 a8 B! \# A. p+ a) v2 x
+ T3 n6 [& c$ I3 H$ H+ I P
首先我们新建一个工程
+ V/ Z, u' i4 \. [9 y* j h% T. g& A
/ j- j1 V8 m) R. }/ a
& `$ Y0 T4 W& |: n- j
在第二步选择路径
" `5 Q8 j8 e% F3 B
# {$ `; S! d( k
: d( g- p1 i$ [. r
第三步直接跳过,第四步选择我们的芯片,芯片型号为XC7A35TFGG484-2。
2 o4 m. S6 L9 @" J# l
5 ]! f e0 |8 r; h9 Q8 k$ x
* |. ~. T. M3 g* r& J0 O
选中型号之后,点击Next。
( e/ s% R0 Z! I
工程新建完成之后,开始新建文件。
8 A9 R+ L$ q- a4 O. x
0 F) v8 Z: B( u0 s; \# g
首先我们先新建IP核,打开IP Catalog,在窗口搜索block
& Y; A: `/ S: @4 B# p# c
' N% G, r6 {: A' B( h2 J p! d8 H: S# J& l. j4 H1 {$ Z, @8 z, y$ z. m
, @) T8 k' |2 |- [# f4 L# e( Z
4 g, |$ O. w* x1 y
找到如图所示选项,然后双击打开。
3 Z9 L8 y% D; ]
7 T8 _; }7 k" ^2 n, j: u$ v1 w* y1 Y
我们在框选的选项中,选择Single Port ROM。这个选项中总共有五个选项。第一个为单端口RAM,第二个为伪双端口RAM,第三个为真双端口RAM,第四个为单端口ROM,第五个为真双端口ROM。我们此次使用的是单端口ROM。
( k3 ?7 U& w7 \% `4 ^( X; q
" W$ ^# z! B5 ^" h( D7 m) L
3 `# M P; ~) b: } K) X' v1 ^! ~% ?) G$ c, O0 U5 [
图中框选出了四处,第一处需要我们修改一下数据的位宽以及深度,位宽我们默认使用8bit,深度为1024。因为我们在前面做了一个数据量为1024的.coe文件,所以这里深度改为1024。第二处为数据输出使能,在此我们选择为Always Enabled。使我们的输出使能一直有效。第三处为输出寄存器,输出会在时钟下输出,导致结果会慢一拍,在此处我们不需要这个选项,因此取消勾选。第四处为ROM复位的设置,如果有需要,可以进行勾选,此处,我没有使用复位信号,大家在使用时自行选择。
# c. z2 F' v. P/ B
; g/ t; X( i' A2 O3 a% F- e0 T4 _& @( h8 O
此处我们需要勾选中加载初始化文件的选项,然后点击Browse找到我们提前生成好的数据文件。选择好之后点击OK,生成IP核。
7 F3 J5 V" J/ Y" N6 l( A5 {/ Y& P0 s
& e- q& ^; `9 l6 _$ S" _* N, k, o% B+ [
, e: Q Q1 B1 A f) M8 R. l( {
直接点击Generate。
. U7 t& I5 `+ ~ t# K
$ v9 D3 n* u- R9 l6 q: N7 L7 M
IP核生成好之后,我们新建文件,写一下我们的地址控制模块。代码如下:
; J, ^: L% n7 w7 m' J8 H
. Q7 C9 [) o. D- r( @
, `* ~, p" V! w) `
然后我们新建顶层文件。写好端口之后,我们将IP核与地址控制模块例化到顶层当中。
; k. r, O @1 g1 R
, t1 {1 M$ S0 x8 x! \1 {
6 l* @' U* |5 s" n, H
点击Next,选择Create File,新建顶层开始写代码。
$ p. e+ B7 c# J5 d* n! C5 ?
) o% b0 k! w, n5 N; c3 ^
; ?3 \6 K% b% T
0 ~& \& C" U, Z w7 W* h
( x- a1 V( O t6 |
点击Next,选择Create File,新建顶层开始写代码。
, i% O% X. t: w1 u8 e5 J
" h: K4 M, ~& k6 }9 j
' [- [4 ?* k, o9 T& B) d
复制粘贴到顶层当中。地址控制模块也同样进行例化。顶层代码如下:
% u6 e8 j9 j2 {( h
1 |4 ^* r: F E' S1 h. D* Q0 R8 }
代码写好之后,保存编译,没有错误,那么我们写一下仿真看一下仿真波形。
$ e B: j3 u0 \; A: `/ P
1 [, \. V3 T7 B$ { D& D% e- ^1 j: ? R |
选中新建仿真文件,点击Next输入名字。
8 w6 T" `9 L( f# L8 V5 i
. Q. @ E6 I" A
: a2 G/ B, i& g7 D! a
点击OK,开始写代码。仿真代码如下:
) @! J6 ` o" m! J+ V7 Z
' b2 |4 H- {. Q/ p7 h
7 K* h5 b# ]& f: {* \, M# j+ n {
代码写好之后,打开仿真。
J4 E+ j' ~2 @ p: G! u
$ ?4 a, W: ~, }2 @
" ?- }6 W! _( r6 Q
波形窗口打开后,点击run all让波形继续运行
, Q" }) S0 P) F- o0 j
) a( o% o4 x' |# H
' a( `$ t9 h O7 D& a. `$ F* b
然后看到如图所示波形。
) s0 \( x; c$ ^: \ Q& B, A
* b2 ~* N! a/ i% Y
8 j1 j" s7 D* w9 J4 ]+ @& e
6 ^2 i' \2 K3 M3 _0 R
然后选中输出q,右键选择wavaform style,然后选择analog就可以看到我们的数字信号就变成了模拟信号。
& ^% y0 ^" A3 k$ w+ N( f; `
8 ]" O2 f& }! e* q) C1 P* r- m: Q% O9 R0 P# g& y# o+ X# d+ S
但是此时波形只有一部分,我们再次点击run all ,然后点击break
3 M3 @1 I6 ]# G- u1 m/ t8 }
/ f8 T7 t: Y9 y1 K) B5 f
% \% f/ \8 H$ b( u
- V+ V# f, R* v$ s v& j. L
就可以看到完整的正弦波。
, F a O4 h! f
a" Y/ ~) Y0 {$ Z
5 D6 `6 B0 C3 S5 u: w
我们的数据文件就是做的正弦波,仿真显示正确。