ROM的英文全称为Read-Only Memory,即只读存储器。可以从任意地址上读取数据,但是不能写入。那么我们ROM中的数据,就需要我们提前存放进去,在IP核中,我们可以通过.coe文件进行数据存放,文件格式我们可以参考Xilinx官方标准。
0 ^2 N! _2 {9 H/ ~3 p6 O
数据文件的格式是固定的,我们在填充数据时,需要严格按照官方的格式进行书写。
2 h1 H8 e. U5 n# z! E$ i+ p6 A" n9 D
3 x" q( f& ]5 i" P6 M; z( K( c! z2 ^. s4 Y4 y
在示例文件中,第一行规定了数据的格式,此处规定的是二进制,那么下面的数据,我们必须用二进制的形式。大家在写的时候,规定什么进制就用什么进制。数据与数据之间用逗号隔开,最后一个数据用分号结尾。
! u- i% ]- Q- b
了解了数据文件格式之后,接下来我们提前准备一个数据文件,以便于后续我们调用IP核去使用。写数据文件的方法有很多,在此给大家介绍一种:MATLAB。
: ^+ R7 ]8 F) `$ m" _% M- ]
% s. l# J" O6 P3 O2 Z7 w1 a我们打开MATLAB之后,首先先选择一下工作路径,以便于我们去找到我们生成的文件以及保存我们的代码。如图:
' `' N. y* A( u
4 G( R) n/ _5 d$ v2 n/ s4 C
% X" p2 [3 E+ F% {& \ \
8 B7 B3 x. {$ b
打开如图所示的图标之后,选择好工程路径。
l7 Q R! Q2 S2 W4 o
2 M J+ f w C2 O& g6 I
选择好之后,我们新建脚本文件,然后写入代码。
2 l' D E8 _5 \* P( X2 C
2 t1 S! Q7 d2 U2 d ^
" V6 j3 ~( a4 u8 w
1 \4 X) J# R# I; r6 ]8 @. F
4 `! }7 O0 V* m" R
写好代码,点击运行,即可生成我们想要的.coe文件。数据文件准备好之后,接下来我们就可以调用IP核了。
0 {8 n% G: a, g) d9 M1 l0 k& p
% I( {/ l" d r' ]0 O/ T
首先我们新建一个工程
5 b7 b# l j/ ~- \# I" X
* _9 g: ~# Q7 l7 L
5 [* h. Y8 T9 a" m, R" e; E
在第二步选择路径
; u- d( V; d& _ O0 |7 b* B
2 ~/ r3 I1 O. J. n1 k
+ K. U7 U/ R0 E( }
第三步直接跳过,第四步选择我们的芯片,芯片型号为XC7A35TFGG484-2。
. o) l3 d, m" g8 f+ w/ Z
: T+ ?& f- v0 z# R9 j- _. \
1 R, B1 `+ a- G; ]' P# t, Q
选中型号之后,点击Next。
9 U; n3 \' a q
工程新建完成之后,开始新建文件。
4 B5 |# u. H' V. o, O
) Z9 k$ U* q3 s! Z' X/ u x首先我们先新建IP核,打开IP Catalog,在窗口搜索block
" \/ D$ t$ M# I2 b
- ?( b C# @- Y: k, I+ {2 y/ b% S4 e- _3 @" a& w, b) x& W
& Q9 v' G W$ \* ~9 Y+ {6 o! q& v# g+ P/ `1 Y: R/ V% Y1 I4 Q
找到如图所示选项,然后双击打开。
' L) d( M% a( }& l, T, S& Y. g
. W4 Z2 a% I5 B: r3 e
+ s8 p$ \# L; k# f' I
我们在框选的选项中,选择Single Port ROM。这个选项中总共有五个选项。第一个为单端口RAM,第二个为伪双端口RAM,第三个为真双端口RAM,第四个为单端口ROM,第五个为真双端口ROM。我们此次使用的是单端口ROM。
- ~) `6 w6 U, [5 Y6 W; Y
2 `: X# p! Z0 s9 c+ d3 }
9 s1 [ x9 b; |6 K4 k9 I
& [% A: C* v$ g
图中框选出了四处,第一处需要我们修改一下数据的位宽以及深度,位宽我们默认使用8bit,深度为1024。因为我们在前面做了一个数据量为1024的.coe文件,所以这里深度改为1024。第二处为数据输出使能,在此我们选择为Always Enabled。使我们的输出使能一直有效。第三处为输出寄存器,输出会在时钟下输出,导致结果会慢一拍,在此处我们不需要这个选项,因此取消勾选。第四处为ROM复位的设置,如果有需要,可以进行勾选,此处,我没有使用复位信号,大家在使用时自行选择。
5 Q- q- S. T1 ?& k. a
1 k1 B' L0 ?) W6 T g" K" s8 F. b3 L! z7 v
此处我们需要勾选中加载初始化文件的选项,然后点击Browse找到我们提前生成好的数据文件。选择好之后点击OK,生成IP核。
- `6 B7 ~& h; P$ K" [8 @( S
' _/ c& z# K6 H0 p6 J! T/ J
4 N1 M( @* N8 T% b0 }* ~
/ _; ^5 T( _3 m
直接点击Generate。
0 R5 {- X" b0 `; ^( |0 j( g
8 V3 V$ d) U5 `0 ^& b! C0 O' I
IP核生成好之后,我们新建文件,写一下我们的地址控制模块。代码如下:
7 T+ J% ^4 ~# \2 i
, d" }: V$ i1 z2 x! k3 B4 a. e4 l B2 f# S( H& l0 o- F1 [4 o
然后我们新建顶层文件。写好端口之后,我们将IP核与地址控制模块例化到顶层当中。
+ M7 U2 I& r* [: p( O4 _
* s3 b, ~# @1 s9 ^. q N0 m
3 {7 N' z# n1 [
点击Next,选择Create File,新建顶层开始写代码。
4 }4 _* O- M: {8 ?% r
2 n& \1 S3 m9 ^" Z! P" \( Z. W6 q. s0 ?
* D0 o+ {7 v( H0 f. b- r% l( E) l" K
# Q) d9 N4 N0 W% b0 ]4 B( a. o
点击Next,选择Create File,新建顶层开始写代码。
9 @( ~5 g4 _7 M3 U2 c
/ j& Z6 C6 @8 i- l( t) e5 v
6 {7 v# q8 v; x; ?0 B+ o6 f
复制粘贴到顶层当中。地址控制模块也同样进行例化。顶层代码如下:
% m k) F3 b1 i0 Q: v' |
( A# p/ b2 w3 o9 d. I' h' s, O/ s9 I: l
! y! m5 r$ Z4 m5 X5 X
代码写好之后,保存编译,没有错误,那么我们写一下仿真看一下仿真波形。
+ S: z8 b7 w: {- b5 t
* a9 y2 w3 [4 c9 w K
: Z' x8 J! G. o0 A
选中新建仿真文件,点击Next输入名字。
: ?) e c5 e- f) M% s5 e! d8 @
( X* v3 k6 ]# P& D2 }# E* E0 |2 ?/ m2 N
点击OK,开始写代码。仿真代码如下:
8 g( X- I# u i7 K! v! H
# p9 I; W1 H$ n4 `1 C0 d! c: [; u9 p$ _( P& ~5 }
代码写好之后,打开仿真。
6 W) B- P( b- {3 j8 _
$ I3 v* {- G8 r6 k2 j1 o# t2 o! ^
* ]* J7 @) }$ O- A/ l
波形窗口打开后,点击run all让波形继续运行
: ?2 M6 {5 h4 \2 G
O+ `* w7 y% M- B, G) I4 b: ~
3 k2 m7 {5 i' E3 c; Q" ~
然后看到如图所示波形。
1 U6 }/ U3 D) ? |9 {% M
$ H9 k3 C2 V9 E/ D3 x* ?# Z1 a) n' I# {& r7 _' ]' h
6 N2 V8 R6 ^7 d! p' K4 ?1 A5 v
然后选中输出q,右键选择wavaform style,然后选择analog就可以看到我们的数字信号就变成了模拟信号。
* o& U; Q( L r
. q3 [' }: a" {7 Q' M
. }$ R* z& W6 W1 X0 n8 M
但是此时波形只有一部分,我们再次点击run all ,然后点击break
3 k0 J8 m; ] k4 K6 P* G3 [
, v# r+ }* @9 C* I2 V5 n- O
/ O, y8 z( _. A& X; D/ _) y: s6 t
( ]$ W+ C3 P3 E% O* S& O8 _
就可以看到完整的正弦波。
. ]* e5 k& F! V/ X/ A+ A
, c! R! H Z: F9 d A/ t+ o
7 O. h' I, U/ J- \, o# v/ m9 u; y/ K
我们的数据文件就是做的正弦波,仿真显示正确。