EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 FPGA技术江湖 于 2023-3-13 16:40 编辑 + ^7 I/ a! G: m1 l$ N7 M
& k- ~/ \/ }. K L, e' U
6 e) l- q6 i# L7 f' r4 i
本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
3 o, C: I" }3 b
! Y& i8 _ v @9 I, [, @+ \
. q2 D/ K# n* l. g 系统性的掌握技术开发以及相关要求,对个人就业以及职业发展都有着潜在的帮助,希望对大家有所帮助。后续会陆续更新 Xilinx 的 Vivado、ISE 及相关操作软件的开发的相关内容,学习FPGA设计方法及设计思想的同时,实操结合各类操作软件,会让你在技术学习道路上无比的顺畅,告别技术学习小BUG卡破脑壳,告别目前忽悠性的培训诱导,真正的去学习去实战应用。话不多说,上货。 4 ^5 k2 M/ a, J, e+ w8 n
9 t8 u' b% u x( c- Y9 d( W. m; Z
/ G8 c* l! e2 m8 V% F
; z) S; `' p2 S$ ?# cIP CORE 之 ROM设计
( ]; W) r% Y( P, {9 v) C/ K: \
2 O. b! s) j0 y1 ]; y9 Q! u1 S& L
?0 Z# g% Q) T, B8 p- C
7 K% x# q% e" _. b- | o$ \. A
本篇实现基于叁芯智能科技的SANXIN -B01 FPGA开发板,以下为配套的教程,如有入手开发板,可以登录官方淘宝店购买,还有配套的学习视频。
6 \- u+ g% P* R% A
( {4 R F( `" ~% N" j+ G9 `
0 A5 U8 x: l) x$ I6 m. I) [: J( M! k7 j
' b1 C* I& W9 r- @. T9 M
. g" |* N, M, j4 Y7 @# ^- b/ M- a1 O1 I! B& ?) x: L- o% O
* z! k2 N' W+ aCYCLONE IV系列器件采用嵌入式内存结构,用以满足设计时需要芯片上内存的需求。嵌入式内存结构由M9K内存块组成,在FPGA中按照列状排列。设计者可以配置这些内存块成为各种内存功能,如:RAM、移位寄存器、ROM和FIFO缓冲区等。 : P5 `. g- t2 t: l/ z3 t+ a" a3 p
. f: T4 e6 I# x9 B+ V
5 A* t; e0 V6 g' E0 G. A/ ~0 BSANXIN-B01的FPGA为EP4CE6E22C8, 此款FPGA共包含270K bit的内存。 / B' ?5 ]( }4 c8 B1 d
+ Z3 G% M5 r* p4 j0 V $ K- `2 {+ Y6 y* x3 @
+ q) U* V1 }0 `8 F; Y' ~# a9 E$ O
: U3 ^. {) W7 @2 ^
- n: K5 b5 k5 Q8 V3 [0 \ 4 d9 y2 f. _ n: X) g9 }
M9K的内存块支持以下特性: ( Z* M) Y( Y0 k, j) X8 T: N8 H
/ x1 N7 m, ]4 S( P9 m
1. 每一个内存块有8192个bit(包括校验的话,就是9216bit) 2. 独立的读写使能 3. 端口可配置 4. 支持单端口和双端口模式 5. 支持字节使能功能 6. 支持时钟使能功能 7. 在RAM和ROM模式下,支持初始化数据
/ Z( n2 z+ D# H {: ]( d7 S
片内的M9K内存块是由RAM构成,掉电丢失。 ' `4 @2 }& C' ?! @
& K+ y7 F! z+ f· 设计要求 在FPGA内部构建深度为256,宽度为8的ROM。在不同的地址中放入与地址值大小相等的数据,即:0地址放0,1地址放1······
* t# s# v" C" S# a. F8 Q0 _
# A% _6 g+ }3 C! m n9 y8 z! L· 设计原理 ROM(read only memory)只读存储器,此种存储器不支持写操作,只支持读操作。在存储器建造时,将数据刻录进去。ROM能够实现掉电不丢失。 ' z4 ~' y8 r4 R- i/ `! l6 N8 q7 ]
% Q. [$ x+ @8 e/ R; w) y" d
本次设计ROM是利用FPGA片内嵌入的M9K构成的,所以不能够实现掉电不丢失。 , j% v# w; d7 k/ d
$ d8 z/ R6 G F; K. c7 K
由于设计ROM深度为256,故而地址的宽度为8位。 $ Z* y( D1 A9 t4 p8 B
4 w2 {- Y3 b/ M0 e' D
本次构建为ROM,所以在构建ROM之前应当首先设计好初始化文件(mif文件)。 ) Q, k \ L+ E# j
8 [+ g( i8 X( M: A+ A( U( r- JROM工作原理为,在时钟上升沿采样到rden为1时,将addr所指示的存储空间的数据进行输出。
+ h- X3 `- { H2 r8 g& R% [& k % N8 j4 Q0 Y$ h7 n- C& g
· 设计架构和信号说明
6 Q. W, B9 t$ |9 v# l \本模块命名为rom_test。
7 K7 o0 a: M, x7 h' z " ?5 w& w- P9 q1 ~
1 U2 ~( i/ y" @4 }/ J# _9 y- G# M, F( A
' P% L" _( }1 r7 q. B# V% ~
! B/ J2 L! I$ a: Q* ^9 p8 x 4 `. x: E- K J+ C# E! p
4 S* }3 D, l% j6 I
4 q7 M4 d3 B* }8 |, l
, p; u8 L5 ?! e; T% R | . p8 Q5 A+ D' p7 I, Y! G
& R5 J- F& M1 q5 l! H, e0 _
· 制作初始化文件
8 F. Z& S' m1 U( ^ ?2 i/ r) Y% X建立工程后,在qprj文件中,建立ipcore文件夹,在ipcore文件夹中建立rom_my文件夹。
4 Q0 i8 ?( Q7 a r: [+ U( v% l8 V 7 a$ L. |9 O+ T) ~
新建mif文件。 2 O7 u' Q8 V9 q% |0 R3 g
+ p* L" g0 e3 c+ X& S8 Z
, c; M* N; Q3 X3 C4 ?; |+ A
0 i# C0 U9 Y8 a4 w% ]7 \. h7 ? 3 r$ B7 _' ?0 ~9 i1 ~3 U+ {
/ H. M$ H( \3 j3 m+ N2 h1 a& k( F: L
点击OK,输入深度256,宽度为8。 - F; I6 M4 D: g
- C4 W" T5 p& T5 C9 `/ h
! q. [' L8 [3 \4 u9 P
2 N! Q: I B. \$ g1 _: m9 G2 j
( _$ N6 V, ?# ]% [( |) p
; s3 `8 r f$ [4 ]
" L: f: J* ^( V& Q+ V点击OK。然后将点击另存为,将文件保存至qprj -> ipcore -> rom_my -> rom_my.mif。 7 j6 f! Y% M! ]2 e2 F( j5 g
! ^3 q" I1 ]3 L8 s: t c7 N2 D& Q. v" u! p# j) ?8 e
# ^; L/ P$ Q# {* _
- I8 f; F& m$ k' E
# Z o9 f1 k, s O( n+ l! W
这里的每一个小方格都是一个存储空间。排列方式按照基地址加偏移地址的方式分布。例如:图中选中的蓝色方格的地址为32+1。 ; h( c% [, G$ M8 Z* h
5 c5 y* `9 k" B$ C& F
在基地址或者偏移地址上,右击可以更改地址的进制和存储空间存储数据的进制。 0 G9 U5 C/ q0 Z) B* M R
1 Y3 |5 `7 b1 s7 C( w' y
* l& G0 f5 _) ^
0 f4 K# N$ E' F* {8 S1 y' I; A
/ E. w9 \6 R- ]9 q# `
9 o! L9 O6 E7 H: N* ]3 l将地址和数据的进制都设置为无符号位十进制。选中一个单元,可以直接进行数据的输入。由于存储单元有256个,每个存储单元都进行手动更改的话,确实比较累人。 , @2 |: w5 o- X( D5 s3 S& T
( C B+ S+ z; M- O( A* U在存储单元格上右击。选择custom fill cells··· + y q: K+ G4 `) `1 N3 f4 q6 f7 y
0 p( c6 J9 |1 l: |) B& d5 F4 ~
$ f3 \% L& S+ j% E9 i x, [: E% H! p1 u/ u
3 Y! A5 j$ X. E$ I( b9 Y) a) K$ {6 p, p9 r) F5 c0 d2 E
这个工具是quartus 软件为方便用户有规律填充存储单元的快捷工具。 " ]2 {) L9 a# ?5 A( k
$ L+ R* O. Z: K% c
初始地址填写为0,结束地址填写为255。 ) N9 b( `$ a3 i- ~& O: e5 _& _
6 b9 z2 T7 N2 z( P# C
选择递增或者递减,初值填写为0,选择递增,步进为1。 ) M& a7 v: l, N% v7 O7 f( I- K7 R
& R& E0 F) u4 H) V9 f; M0 M点击Ok后,就可以看到,每个地址里面都会填写如与地址值大小相等的值。
# x1 C$ S9 f% U+ ~3 Y5 j5 R | 0 K1 H g" c" E% H; t
5 ^$ d) z. D( c5 u
2 u. l1 U; s% G4 z% M5 B) J) A. j
1 v! s2 M" y0 X5 q0 j4 ]' R) x
- \# p* p2 { M' d
点击保存,mif文件就已经制作完成。
3 p" ~! A! p @& g7 j; l; q ' B% V9 x2 q" O, ?
· 调用ip core之 rom
3 w' t0 d1 m1 ` {6 T7 ]选择tools -> ip catalog。 * v6 X' `( t( ]6 Q- }
+ u5 Q" K; n6 s2 C9 Z* A3 y0 Z% P
* ?: \: @$ X V' C# R2 v) [* O
/ f% g. S1 b! B$ L, I& I6 Z) c. m0 A6 G- q/ \1 F: J: A
: _# U! t, G- ^5 J- A5 W; @
ROM分为单端口(1-port)和双端口(2-port)。ROM是一个只读存储器,通过给予地址和读使能,就可以得出对应的地址的数据。在FPGA中,ROM可是配置两套端口,这两套端口相同,都可以通过给予地址和读使能,得出对应的地址的数据,并且相互独立,但是共用同一段存储空间。 6 a1 L3 c5 n% L2 @
+ S) k h; ?4 i# P$ { j1 }$ L: ]
在此选择ROM :1-port。 * X( ^' y) E' ^+ O) g! F7 C. `! E
. P$ K' F# i& b# J" a6 t1 ]选择verilog,路径为qprj -> ipcore -> rom_my,名字为rom_my。然后点击ok。 # Y9 P; a. p- j) x
9 [5 Y" E: r- G
0 L' |3 k: O/ ^3 B" i+ U- w6 p* F G
# u7 \9 F1 a# q
w. \" X" V) h, r: _: l
/ f( t6 r. k& a4 Y选择深度为256,宽度为8。 & ~$ L( f5 R) H4 b9 W
. T7 u! E% s- D- D5 g& f& w( y) R
选择时钟方式为单时钟。点击Next。
8 N! H" J. ~* `1 e6 ]/ C! o4 j
/ c( N! m: T. }0 v! ^* Y7 E0 s
& {) U$ `. L" K) U' x( j( u3 z
选择 q out registered(即经过寄存后,输出q)。 k8 b, C3 I% i
' W& _- k7 b+ [- p: y T* K
选择读使能。若不选择读使能,则读使能一直为被使能。点击Next。
3 ^- B$ H% b/ B
9 p0 j/ G6 ?! ?3 u) n6 P" P& B% ^. O. h+ y+ n/ T
. R# i0 t p. Q- r: b( I/ C
# r% V1 V* s1 R2 D* f6 g+ ^选择browse···,找到qprj -> ipcore -> rom_my -> rom_my.mif。
! v: e) U! |/ X, T( p; S
) z7 R8 E! h9 i7 m2 i3 g) j* D在此文件中,找不到该mif文件。因为寻找文件的类型不对,将type of file 修改为 all files。 7 F; E) O$ p+ |; |6 S! F
4 e& J9 E) D' \$ C* T. V找到mif,点击open。 5 v9 l @/ t+ N3 B
$ ^; v9 z" |5 n5 U( x( y1 D1 V
点击Next。 1 |. k9 R' @6 a7 y0 |
7 m1 ^$ c. b+ \
4 Z6 a$ |6 b( g/ Q. S
" c, f9 }" c# o3 i8 @) {/ ^. z% m% }6 c4 V" F8 u4 I7 C
$ Y' d) `, t8 I1 C/ A; n
5 n0 {4 M, ]4 l% Y; O9 v
( t/ j8 ?; f- O8 y+ M' P! a$ c1 X ( J( A: \: X% I2 A2 k
% a! o5 z" m. N) s, \4 s
2 A! `3 } ^! N5 Y. A
/ x' n- F( Y! B" p" y7 y$ N
( D) z3 x, c- N
7 a2 U" K. V1 k
* C! Z4 }/ t- a+ _点击Next。 ( F/ y3 F8 ~7 M
( v$ C# Y+ o; z" i+ a# O
$ E% S8 j4 O b; \* H; q) A( U
5 p( }7 ~) H: P0 P* Z0 E; e' u# S' {/ l. k2 h5 J6 o
选择上rom_my_inst,点击finish。
5 c/ [) N6 S7 b2 Q
x( [; M' E& N. z. W3 c
X: n+ T# K5 M# o0 W' _
+ h' [# o0 y9 y& O; S. {
% r* M( K I7 u0 }! A6 m. J6 D
3 b( i7 Q, `4 s: Y, j9 _+ j9 |9 {& c- n4 c3 `# p8 {
把这个ip core添加进工程,点击Yes。
; n0 u5 W" I- _/ [$ L5 d0 s6 S6 |
# B" S; ^" q, w/ g4 J4 }- q
: o) ] j+ p, f4 Y
& H: H: K6 e7 b· 编写设计顶层 / `7 H- _4 T2 b$ m$ y9 q5 q
顶层模块负责例化rom_my。rom_my的例化代码在ipcore -> rom_my -> rom_my_inst.v中。
: @' ~( B, A8 n! ?% F0 D2 {0 u
9 j% m2 V0 p3 T5 M& V) A# z设计代码为:
2 j+ n0 J+ J7 J& C7 p, f5 q
! Z& R5 o! l, [0 b( G$ W/ m% D8 n( H% ]& |
! v! l, g h% u+ I+ f
: B6 v; ]$ _8 U) {
4 {0 E: P8 A/ Q9 H" b* f) l
$ }# v! G, V7 s+ |分析综合后,使用2048bit的存储器。报告如下:
) T" H0 Y4 R0 n6 g. p, o. j. \+ ] . X7 U z( I6 S8 b- i
! V! ]1 ]( t! |% r! u0 Y$ `) O8 h2 z. B4 a, }2 {2 A
1 i: z) s' w, s3 |( W· RTL仿真
/ Q. k/ Y3 i v$ V, u 设计仿真文件时,将所有的地址轮询一遍,查看输出的数据是否正确,rden信号设置为随机值,在不同的地址随机决定是否读出。
' U7 Q9 ^4 {" b# l1 G+ _* e0 w" I仿真代码为:
# ~* g- H, j; R2 f9 Q 7 A6 |0 g3 x2 J3 D1 @6 E
6 d" |1 w5 ?4 ~8 g
6 _2 I5 E/ V. M
4 q- I3 L4 |- u% j0 X/ R5 Y repeat语句为重复语句,相当于把begin end中间的语句重复执行N次。 - L; C% O m' h) C+ q1 T3 X" G
. t2 x }9 w+ g, N; Z
设置testbench后,进行RTL仿真。 ( Z% W; L# E& G/ U
( J0 A& I) H/ M) e8 a1 b6 a4 r3 r& C/ p. \6 T- |
9 N8 q' l0 v9 G, c
}( I9 B! H! f5 w( t# | 从波形图中可以看出,无论地址为多少,rden是否为1,rdata始终为0。
/ r& f/ R( A9 q) n, E
* R* i# Q- Y& d2 _0 y( y 打开modelsim的transcript窗口,就可以发现原因。
3 `6 d+ n7 P6 R: }) z, n* T% [ ( D+ l7 K$ ^5 k6 A+ V# ~# ^
modelsim的软件打不开(找不到)初始化的mif文件。 1 f- k; p& A2 b6 n! d
0 @' x9 g& y# |3 R: @/ G8 q4 p2 p
. K- i6 a; W4 f7 S2 n9 @* m& [$ p$ s 9 G L7 m7 _: m% q, Z: b
出现此种错误的原因为,modelsim和quartus的有很多文件在进行关联是都是使用相对路径,为的是方便工程的移植。而在仿真时,两个modelsim软件认为的基本路径和quartus软件认为的基本路径不相同,所以导致出此错误。此时,笔者建议大家直接打开ipcore -> rom_my -> rom_my.v,进行修改初始化文件,将相对路径直接修改为绝对路径。 + I J/ ^& \) W
) ?4 S q- x4 M6 X- n+ [+ j 将altsyncram.component.init_file=“”,双引号中的文件前面的路径修改从盘符开始的路径。切记:路径的下一级标识为“/”。 % F- j+ n2 W8 g0 O, N _1 C# @
+ M) c+ M" o' t* J6 S( D2 H) V/ c
( z! i( \8 d! Y( M" z
" s, d/ {4 j, v# o
4 j. a6 ^. A1 S% W 修改后,此工程在已经移植时,就会报错。因为此路径已经不合法,所以在进行移植时,请对应修改此路径。
# {# @" V1 g1 I ! P+ X q) v. E6 f; {- @) l
保存过后,重新进行分析综合。然后再次打开modelsim,就可以看到正确的波形了。
& `% k$ j9 }8 i ?% r' w 4 w; n9 e, U3 \) ^
, t1 G( ^5 u, H: p1 l
& J3 i, Z/ v4 y
' b% m8 m9 O1 w0 X, l
' f$ c" H G2 J; _* R
在波形中可以看到,当rden为高时,rdata能够延迟两拍后,输出对应的数据(当地址为1、2、3时)。当rden为低时,rdata保持上一个值不变(当地址为7时)。其他地址设计者可以自动对应。 3 a9 ]* [' d% b2 s( s
8 E* A/ j7 y1 g+ Z& |! w 将ROM设置为双端口时,addr、rden和rdata会多出一套,操作时序和方法是相同的。 1 ^0 `. Y7 h5 l' W- s* ]0 M4 w1 `2 ?
/ H8 c( t' b6 P6 U. P2 b$ {' v
. ^* [& E) W" [8 f. `3 j' e& Z' m- p/ K$ V; _
; M& s$ G" |. R# o- k% u/ I' z, ~
2 k' M0 m% P C7 h0 P" U8 \. ~ |