在Quartus 下有许多免费的IPcore可以使用,其中存储器就包括ROM,单口RAM,双口RAM,FIFO等。这些集成功能IPcore功能强大,接口简单,仿真文件齐全,配套的设计案例丰富。充分利用这些IPcore不仅使设计变得简单,性能高,而且稳定可靠。本节内容就从最简单的ROM IPcore的生成,配置及使用介绍开始,逐步把相关的存储器类IPcore介绍给大家。在这篇文章中主要介绍ROM的生成与配置。
ROM (read only memory)只读存储器,也就是掉电信息不丢失。大家可能会有疑问,既然FPGA是基于RAM的架构,FPGA内如何做到掉电信息不丢失的?其实原理很简单,也就是ROM的内容随着FPGA上电配置,一起从外部存储器中将ROM的内容写入的。因此从用户的角度看,的确做到ROM的信息在掉电后信息一直保存的现象。为了使用方便,Quartus 提供ROM的生成与配置向导,ROM的生成步骤如下:
1. 新建测试工程
在learning_course 目录新建文件夹test_rom(c:/learning_course/test_rom),工程名称test_rom,顶层设计实体(top level design entity)的名称为test_rom。器件选择Cyclone 10 LP , 10cl006YE144C8G。EAD tool Settings –>Simulation–>Modelsim-Altera。
2.选取ROM类型
在工程的 IP Catalog区域内Library–>Basic Functions–>On Chip Memory–>ROM:1-PORT,如图1,双击跳出界面如图2。

图1
在图2中IP的文件名称为p1_rom,可以根据命名规则给出名称,这里以p1_rom为例。点击OK. 弹出对话框如图3,

图2
3. 配置ROM参数
在图3中设置如下:
-
- 输出的宽度8bits和深度256 words,这主要映射到左边的图形的输出q的向量宽度(如本例为q[7..0]对应8位宽度)和地址深度(如本例address[7..0] 为256 words).其实在选定芯片的可提供的范围内,宽度和深度是可以任意设定的。这里设定的是工程中ROM的使用情况。
- 选择memory block 的类型,在Cyclone 10 LP 中只有M9K一种类型可以使用,如果选择的器件是其他类型如Arria10系列或Straitix10系列,有更多的类型可以支持,如MLAB,LCs,M144K等。可以选择具体类型(用户定制),也可以选择Auto(自动,由系统根据系统优化进行选择配置)。因此对于Cyclone 10 LP 器件选择Auto 与选择M9K效果相同。这里设定的是每个M9K的配置情况。
- 对于M9K的结构,最佳使用方式是1bit x 9K ,或9 bits x 1K,18bits x 512,36 bits x 256等方式,这样可以把M9K的资源充分利用起来。可以作不同的选择观察左下角资源使用情况( Resource Usage)。
- 时钟的设定,根据需要可以将地址和输出设为同一个时钟,也可以设为不同的时钟,这里设为相同的时钟。点击NEXT,跳出对话框如图4,

图3
图4中的各个设置及问题解释如下:
-
- ROM的输出的数据是否需要寄存器锁存? (这个是可选项)
-
- 只锁存地址(这个是必选项),不锁存数据输出如图4,这样的选择在地址确定后只有地址通道带来的一级延迟,例:读取地址8’h0f到8’h1f的值。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
reg [7:0] addr; wire [7:0] q; reg [7:0] data; reg [1:0] rd_st; //状态 always@(posedge clk or posedge rst) if(rst) begin rd_st <= 0; data <= 0; addr <= 0; end else case(rd_st) 0: begin rd_st <= 1; data <= 0; addr <= 8'h0f; end 1: begin //给状态下,addr==8'h0f rd_st <= 2; data <= 0; addr <= addr + 1; end 2: begin //给状态才得到 地址 8'h0f的值。 data <= q; if(addr == 8'h1f) begin rd_st <= 3; end else begin addr <= addr + 1; end end 3: begin data <= q; rd_st <= 0; end default: rd_st <= 0; endcase |
从上例可以看出,在状态0给地址addr赋值,在状态1时addr的输出才得到地址值,而ROM有时在clock的驱动下的地址锁存,因此ROM内的地址address的输出也延迟一个时钟才会输出,如果如图4的结构,q端没有寄存器缓冲,逻辑译码可以直接输出。
-
- 如果q端也有寄存器锁存,输出将会再延迟一个时钟输出。

图4
-
- 时钟使能,主要考虑到低功耗模式,如果设计的产品将来会运行在低功耗模式,需要深度睡眠状态,就要添加时钟使能端。当然时钟使能添加后,IPcore的使用也变得相对复杂。
- 选择是否添加异步清零端口aclr,该端口是针对address及输出端q的寄存器而言的,即在添加了异步清零后,可以通过异步清零端口清除寄存器的值。这里没有选择异步清零端口。
- 选择是否创建’rden’端口,如果选择创建该端口,在ROM读取的时候rden必须为高(逻辑1),输出端口q才会更新。如图5,

图5
在图5中点击Next,跳到对话框图6,
4.ROM 的初始化文件
图6中的设置:
点击Next,跳出图7 对话框。

图 6
图7 提示

图7
在图8中选择需要的文件,如p1_rom_inst.v,p1_rom_bb.v。

图8
点击Finish , 完成ROM的生成。
关于如何使用ROM和*.mif文件在后续的文章中会继续介绍。