当前位置:   article > 正文

基于Xilinx的ROM IP核的使用_xilinx spi rom

xilinx spi rom

1.ROM的介绍

ROM 是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据的固态半导体存储器。其特性是一旦储存资料就无法再将之改变或删除,且资料不会因为电源关闭而消失。而事实上在FPGA 中通过 IP 核生成的 ROM 或 RAM调用的都是 FPGA 内部的 RAM 资源,掉电内容都会丢失(这也很容易解释, FPGA 芯片内部本来就没有掉电非易失存储器单元)。用 IP 核生成的 ROM 模块只是提前添加了数据文件(.coe 格式),在 FPGA 运行时通过数据文件给 ROM 模块初始化,才使得 ROM 模块像个“真正”的掉电非易失存储器;也正是这个原因, ROM 模块的内容必须提前在数据文件中写死,无法在电路中修改。

Xilinx 推出的 ROM IP 核分为两种类型:单端口 ROM(Single-Port Rom)和双端口ROM(Dual-Port ROM)。对于单端口 ROM 提供一个读地址端口和一个读数据端口,只能进行读操作;双端口 ROM 与单端口 ROM 类似,区别是其提供两个读地址端口和两个读数据端口,基本上可以看做两个单口 RAM 拼接而成。

单端口ROM如下图所示:

双端口ROM:

2.IP核配置

关于IP核的配置如下图所示:

首先打开IP选型

然后搜索block

然后双击,我们选择单端口ROM

这里选择8位宽,深度256,总是使能。

定义了一个0-255的.coe文件,然后并添加

在Summary界面可以看到自己的配置

然后点击OK,我们的但端口ROM IP核就创建完成了。

3.IP核的使用

本次实验任务是参考野火征途Pro系列开发指南,设计一个ROM 的初始化数据是 0~255,也就是存入数据0~255。然后每隔 0.2s 我们从 0 地址开始往下读取数据显示在数码管上,我们再利用两个按键信号来读取指定地址的数据,每按一个按键就读取一个地址的数据显示在数码管上。再次按下按键后,以当前地址继续以 0.2s 的时间间隔往下读取数据并显示出来。

3.1实验分析

根据实验任务我们可以知道,本次实验需要使用到的外设有按键以及数码管。按键的话肯定需要消抖模块,数码管的话是需要数码管驱动模块。在按键跟数码管中间的数据传输时通过ROM IP进行传输,所以还需要设计一个rom控制模块。模块框图大致如下:

消抖模块、rom控制模块以及rom IP的系统时钟以及系统复位端口没有画出来,正常都应该有的,这里需要注意一下。

按键消抖模块代码如下:

  1. `timescale 1ns / 1ps
  2. module key_filter(
  3. input sys_clk ,
  4. input sys_rst_n ,
  5. input key ,
  6. output reg key_flag
  7. );
  8. parameter CNT_MAX = 20'd999_999;
  9. reg [19:0] cnt_20ms;
  10. //20ms cnt
  11. always@(posedge sys_clk or negedge sys_rst_n) begin
  12. if(sys_rst_n == 1'b0)
  13. cnt_20ms <= 20'd0;
  14. else if(key == 1'b1)
  15. cnt_20ms <= 20'd0;
  16. else if(cnt_20ms == CNT_MAX && key == 1'b0)
  17. cnt_20ms <= cnt_20ms;
  18. else
  19. cnt_20ms <= cnt_20ms + 20'd1;
  20. end
  21. //key_flag
  22. always@(posedge sys_clk or negedge sys_rst_n) begin
  23. if(sys_rst_n == 1'b0)
  24. key_flag <= 1'd0;
  25. else if(cnt_20ms == (CNT_MAX - 20'd1))
  26. key_flag <= 1'd1;
  27. else
  28. key_flag <= 1'd0;
  29. end

消抖设置了一个20ms的计数器,当按键按下时间小于20ms就认为按键在抖动时间,根据消抖模块可以看一下仿真代码及波形图如下:

  1. `timescale 1ns / 1ns
  2. module tb_key_filter(
  3. );
  4. reg sys_clk ;
  5. reg sys_rst_n;
  6. reg key1 ;
  7. reg key2 ;
  8. wire key1_flag;
  9. initial begin
  10. sys_clk = 1'b1;
  11. sys_rst_n <= 1'b0;
  12. key1 <= 1'b1;
  13. key2 <= 1'b1;
  14. #201
  15. sys_rst_n <= 1'b1;
  16. #200
  17. //key1
  18. key1 <= 1'b0;
  19. #20
  20. key1 <= 1'b1;
  21. #80
  22. key1 <= 1'b0;
  23. #120
  24. key1 <= 1'b1;
  25. #20
  26. key2 <= 1'b0;
  27. #20
  28. key2 <= 1'b1;
  29. #20
  30. key2 <= 1'b0;
  31. #100
  32. key1 <= 1'b0;
  33. #500
  34. key1 <= 1'b1;
  35. #500
  36. key1 <= 1'b0;
  37. #400
  38. key1 <= 1'b1;
  39. end
  40. always #10 sys_clk <= ~sys_clk;
  41. defparam key_filter_inst1.CNT_MAX = 19;
  42. defparam key_filter_inst2.CNT_MAX = 19;
  43. key_filter key_filter_inst1(
  44. .sys_clk (sys_clk ),
  45. .sys_rst_n (sys_rst_n),
  46. .key (key1 ),
  47. .key_flag (key1_flag )
  48. );
  49. key_filter key_filter_inst2(
  50. .sys_clk (sys_clk ),
  51. .sys_rst_n (sys_rst_n),
  52. .key (key2 ),
  53. .key_flag (key2_flag )
  54. );
  55. endmodule

接下来我们开始设计rom控制模块,代码如下:

  1. `timescale 1ns / 1ps
  2. module rom_ctrl(
  3. input sys_clk ,
  4. input sys_rst_n ,
  5. input key1 ,
  6. input key2 ,
  7. output reg [7:0] addr
  8. );
  9. parameter CNT_MAX = 9_999_999; //0.2s计数器
  10. parameter ADDR_MAX = 8'd255;   //最大地址
  11. reg key1_en;
  12. reg key2_en;
  13. reg [23:0] cnt_200ms;
  14. //key1_en
  15. always@(posedge sys_clk or negedge sys_rst_n) begin
  16. if(sys_rst_n == 1'b0)
  17. key1_en <= 1'b0;
  18. else if(key2 == 1'b1)
  19. key1_en <= 1'b0;
  20. else if(key1 == 1'b1)
  21. key1_en <= ~key1_en;
  22. end
  23. //key2_en
  24. always@(posedge sys_clk or negedge sys_rst_n) begin
  25. if(sys_rst_n == 1'b0)
  26. key2_en <= 1'b0;
  27. else if(key1 == 1'b1)
  28. key2_en <= 1'b0;
  29. else if(key2 == 1'b1)
  30. key2_en <= ~key2_en;
  31. end
  32. //0.2s cnt
  33. always@(posedge sys_clk or negedge sys_rst_n) begin
  34. if(sys_rst_n == 1'b0)
  35. cnt_200ms <= 24'd0;
  36. else if(key1_en == 1'b1 || key2_en == 1'b1 || cnt_200ms == CNT_MAX)
  37. cnt_200ms <= 24'd0;
  38. else
  39. cnt_200ms <= cnt_200ms + 24'd1;
  40. end
  41. //地址
  42. always@(posedge sys_clk or negedge sys_rst_n) begin
  43. if(sys_rst_n == 1'b0)
  44. addr <= 8'd0;
  45. else if(addr == ADDR_MAX && cnt_200ms == CNT_MAX)
  46. addr <= 8'd0;
  47. else if(key1_en == 1'b1)
  48. addr <= 8'd99;
  49. else if(key2_en == 1'b1)
  50. addr <= 8'd199;
  51. else if(cnt_200ms == CNT_MAX)
  52. addr <= addr + 8'd1;
  53. end
  54. endmodule

仿真代码:

  1. `timescale 1ns / 1ns
  2. module tb_rom_ctrl();
  3. reg sys_clk ;
  4. reg sys_rst_n;
  5. reg key1 ;
  6. reg key2 ;
  7. wire [7:0] addr ;
  8. initial begin
  9. sys_clk = 1'b1;
  10. sys_rst_n <= 1'b0;
  11. key1 <= 1'b0;
  12. key2 <= 1'b0;
  13. #201
  14. sys_rst_n <= 1'b1;
  15. #2000
  16. //key1
  17. key1 <= 1'b1;
  18. #20
  19. key1 <= 1'b0;
  20. #2000
  21. key1 <= 1'b1;
  22. #20
  23. key1 <= 1'b0;
  24. #700
  25. //key2
  26. key2 <= 1'b1;
  27. #20
  28. key2 <= 1'b0;
  29. #2500
  30. key2 <= 1'b1;
  31. #20
  32. key2 <= 1'b0;
  33. #500
  34. //key1&key2
  35. key1 <= 1'b1;
  36. #20
  37. key1 <= 1'b0;
  38. #2000
  39. key2 <= 1'b1;
  40. #20
  41. key2 <= 1'b0;
  42. #2000
  43. key2 <= 1'b1;
  44. #20
  45. key2 <= 1'b0;
  46. end
  47. always #10 sys_clk <= ~sys_clk;
  48. defparam rom_ctrl_inst.CNT_MAX = 19;
  49. rom_ctrl rom_ctrl_inst(
  50. .sys_clk (sys_clk ),
  51. .sys_rst_n (sys_rst_n),
  52. .key1 (key1 ),
  53. .key2 (key2 ),
  54. .addr (addr )
  55. );
  56. endmodule

数码管例程就不展示了,大家可以随便使用一个数码管驱动模块,也可以参考野火的数码管例程

最后将这三个模块例化到一起,再进行一个仿真验证:

仿真结果跟我们要实现的任务要求是一致的,说明代码没有问题,这边就不展示上板验证的效果了,下一章介绍RAM的使用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/402673
推荐阅读
相关标签
  

闽ICP备14008679号