ROM的英文全称为Read-Only Memory,即只读存储器。可以从任意地址上读取数据,但是不能写入。那么我们ROM中的数据,就需要我们提前存放进去,在IP核中,我们可以通过.coe文件进行数据存放,文件格式我们可以参考Xilinx官方标准。
, e7 N7 Y( v) z: a. ^7 K
数据文件的格式是固定的,我们在填充数据时,需要严格按照官方的格式进行书写。
6 S% p4 m" J+ a7 ]1 @
' n! V3 x$ @4 N
8 w& @! R3 |+ T5 I
在示例文件中,第一行规定了数据的格式,此处规定的是二进制,那么下面的数据,我们必须用二进制的形式。大家在写的时候,规定什么进制就用什么进制。数据与数据之间用逗号隔开,最后一个数据用分号结尾。
/ ]) y7 |* z) D
了解了数据文件格式之后,接下来我们提前准备一个数据文件,以便于后续我们调用IP核去使用。写数据文件的方法有很多,在此给大家介绍一种:MATLAB。
0 j, B5 f% C* B" t8 o
8 V4 q" t2 g) i
我们打开MATLAB之后,首先先选择一下工作路径,以便于我们去找到我们生成的文件以及保存我们的代码。如图:
* }$ Z, a2 {7 G, B; m; a/ [
/ H) \* U9 d- t9 x3 o
; D- H# O- h) S7 W
( G; x3 i4 h' l+ G
打开如图所示的图标之后,选择好工程路径。
; [' {) }% }' i( ^) {
6 b7 ]" x7 [1 ~- J% p ]2 {9 p3 H
选择好之后,我们新建脚本文件,然后写入代码。
# O# C0 b5 B" ?0 b: M$ s D
3 z# L5 I2 [+ I+ [. y
3 l& d5 F" U5 ^3 U; l& I/ W4 }
" w" N3 E# @: O8 H; J
|% v% H$ i g% o& ]0 w
写好代码,点击运行,即可生成我们想要的.coe文件。数据文件准备好之后,接下来我们就可以调用IP核了。
& C* }% f# M. b; n, R: d
; c, p% b+ [1 N. N& |, s首先我们新建一个工程
. x; h' x1 g$ j! U
+ F* T j0 {& r3 D
+ t4 ^- W! {$ `3 t% Y
在第二步选择路径
3 }/ Q% }/ ^6 e
$ L+ _; _- g5 p h5 L( o: X
) u. e7 f9 I) b/ n. v: y
第三步直接跳过,第四步选择我们的芯片,芯片型号为XC7A35TFGG484-2。
9 }5 F7 U/ I, h( h7 Q, f( O; c* e; \
- A$ o E" E5 B3 Q! b% F% ]6 U9 P, L# i/ h- J
选中型号之后,点击Next。
3 |' @* E3 E- @) t
工程新建完成之后,开始新建文件。
6 [7 U: t" G( Q" T9 F O$ w
5 @8 x" s% {3 q3 u5 _4 |首先我们先新建IP核,打开IP Catalog,在窗口搜索block
) [2 C- ]) I+ R! H! b
% Y( G+ _# i# K5 ]
# X/ m9 D' i/ D0 k3 C1 ?3 Y( r. O
! T' t6 o! T5 c: R; A3 O1 z- ~/ A0 c# W+ |! X
找到如图所示选项,然后双击打开。
! b" t4 q4 Q6 u4 X, p: i1 F
* V& I8 H, @5 j3 G; ]
4 v: n& X: Y+ d; B
我们在框选的选项中,选择Single Port ROM。这个选项中总共有五个选项。第一个为单端口RAM,第二个为伪双端口RAM,第三个为真双端口RAM,第四个为单端口ROM,第五个为真双端口ROM。我们此次使用的是单端口ROM。
8 H$ ~2 I y+ k/ `. r
c4 x6 M, F5 F, B
- B" x* s0 u2 \
$ |/ @' y1 Z; Z
图中框选出了四处,第一处需要我们修改一下数据的位宽以及深度,位宽我们默认使用8bit,深度为1024。因为我们在前面做了一个数据量为1024的.coe文件,所以这里深度改为1024。第二处为数据输出使能,在此我们选择为Always Enabled。使我们的输出使能一直有效。第三处为输出寄存器,输出会在时钟下输出,导致结果会慢一拍,在此处我们不需要这个选项,因此取消勾选。第四处为ROM复位的设置,如果有需要,可以进行勾选,此处,我没有使用复位信号,大家在使用时自行选择。
% c: O4 M* W5 }/ [4 O& Y9 t
( [3 k6 ]" d8 l4 `/ n1 ^2 I2 v- f1 R4 d. D1 p/ H( f# p
此处我们需要勾选中加载初始化文件的选项,然后点击Browse找到我们提前生成好的数据文件。选择好之后点击OK,生成IP核。
0 a( t* G+ O' Q- P7 s5 t0 p; y
0 ^' F9 T' c+ Z @8 {+ ]# c; \
! H# O1 O4 w. O& B
+ ^5 }( Y2 B7 o/ Q+ S- I4 r
直接点击Generate。
* \; v4 J% e) c
8 x) K7 P9 K7 g- V8 h) Z2 n* |
IP核生成好之后,我们新建文件,写一下我们的地址控制模块。代码如下:
! l- n {! V" t4 O7 y' G
* R- B, k& D, J3 a0 V1 F
1 N/ w8 ~ h! c- n1 O* J
然后我们新建顶层文件。写好端口之后,我们将IP核与地址控制模块例化到顶层当中。
@8 ~5 f( B) L# V/ J8 d
, S/ {) n! q2 g8 {8 s# F
" a) H3 s: y# f8 m" R' B* ]
点击Next,选择Create File,新建顶层开始写代码。
) J6 k! u% ?1 f- s7 R# C S
: X, O+ p- S& X
- U( b, W, e7 ]1 n
7 S* C) ~4 g3 `( w3 p
; Q$ y! J( ^% V( g/ Y4 {" S( P6 ]8 `
点击Next,选择Create File,新建顶层开始写代码。
- _ [9 S4 ]7 m! D7 a3 }& p
) j6 x6 _" @/ d
7 ^7 u$ e2 |/ J. K) H" g/ {6 g' F) \
复制粘贴到顶层当中。地址控制模块也同样进行例化。顶层代码如下:
B' d, y6 c( F+ Y1 u1 b0 w
. Y2 w7 _6 d4 w3 E( K+ A4 i2 y# n0 ?% {8 o+ q. ?
代码写好之后,保存编译,没有错误,那么我们写一下仿真看一下仿真波形。
8 A& c6 C% M. X ~1 N! \& D
$ u( L/ M" X4 [+ b& A1 E, W8 |7 E& x5 d9 P9 K7 U
选中新建仿真文件,点击Next输入名字。
6 @3 c R# s$ A# ` u
# W$ y: n: W. Z( d+ E6 n( ]
_& Q# W* c$ W+ D9 ^
点击OK,开始写代码。仿真代码如下:
& V7 A4 I/ z& T* L. Y
; d u- O7 x& E* g9 R& \# I: \" U! B' O- m. R. ]3 T) D, @
代码写好之后,打开仿真。
6 N* y) T( h3 j0 [7 d% ]! z2 K* Q" I e
( ~) F2 |- K/ Y9 V6 k
+ d0 s8 G% P) y k+ `
波形窗口打开后,点击run all让波形继续运行
5 J0 j/ ]7 T r! A2 S% }2 A! c
; b/ [& U: o+ H
( [2 K% X7 G0 ]1 k1 d* X5 D* A
然后看到如图所示波形。
( `$ o1 X. y/ r& B( c6 @3 A
* L7 {. x7 x% K; x+ N. q) g$ J8 e' B* z9 B. G: x$ h
( A p( x. ^# J3 s; h
然后选中输出q,右键选择wavaform style,然后选择analog就可以看到我们的数字信号就变成了模拟信号。
, ^; R9 ]# _) y) K; K! q; [- p
; F- `! z- H# `' Q9 {
, y" [. {( A2 C& r% {8 d% B
但是此时波形只有一部分,我们再次点击run all ,然后点击break
! a! `: E& J7 t! ]' L$ o
# C+ R/ h& [# a
! O/ x5 s `3 b/ E
* f+ ]& n3 P/ ~. }" G7 R
就可以看到完整的正弦波。
# v7 h! n3 D. E: ?# S+ G0 ?8 x, Y
4 P% y8 n5 F2 n% H0 f5 I( N0 z
# C9 S h/ |+ R% u1 Y3 \9 ^
我们的数据文件就是做的正弦波,仿真显示正确。