• 寄存器自动化配置通用案例


      本博文设计思想采用明德扬至简设计法。之前都是通过一些完整的案例来分享设计心得,而这篇文章以需要配置多个寄存器的场景讲述核心设计技巧。

      在设计案例时发现,经常会配置比较复杂的IP核或驱动一些接口进而操作外设。此时,为了让外设或IP核正常工作,需要对其内部多个寄存器进行适当配置来保证在所需模式下正常工作。我们一般先设计接口模块或IP核顶层文件,之后通过控制模块按照先后顺序自动给出所需指令,如读写等(下面的讲述以只有读写指令为例)。接口模块或IP核顶层模块收到指令后完成相应的操作。

      第一个问题:如何实现多个寄存器且每个寄存器多个指令的自动化配置?

      我们可以在控制模块中建立一个“配置表”,把读写指令以及相应的地址和待写入数据保存其中,然后通过计数器进行指令扫描。这里需要两级计数器,第一级计数一个寄存器的指令数,第二级计数器记录已经操作过的寄存器个数。配置表以always组合逻辑中case语句块形式给出,使用寄存器计数值区分不同寄存器。区分出待操作寄存器后根据操作计数器解析出读写指令。

      第二个问题:当控制模块给出指令时,接口模块或IP核一定能有时间响应么?

      这是我们设计时需要深思熟虑的问题:如何才能保证给出的指令一定会被下一模块有效地响应?为了实现这一目的,可以在控制(配置)模块和时序接口模块或IP核顶层模块之间放置一个接口衔接模块,结构如下:

      根据上述需求定义衔接模块功能:在下游模块准备好后才让上游模块ctrl给出下一命令,否则等待。并完成读出的有效数据送到上游模块的任务。很简单,下游模块输出给控制模块一个信号rdy,当它为高电平时代表当前没有指令或者上一指令已响应完成。控制模块中指令计数器的原有计数条件和rdy==1条件逻辑与就完成了上述功能。这里需要特别注意的是:rdy信号必须以组合逻辑形式给出,否则由于rdy信号晚一拍输出,上游模块会出现误认情况。核心代码如下:

    控制模块中:

     1     //读写操作计数器    
     2      always  @(posedge clk or negedge rst_n)begin
     3         if(rst_n==1'b0)begin
     4             rw_cnt <= 0;
     5         end
     6         else if(add_rw_cnt) begin
     7             if(end_rw_cnt)
     8                 rw_cnt <= 0;
     9             else
    10                 rw_cnt <= rw_cnt + 1;
    11         end
    12     end
    13 
    14     assign  add_rw_cnt = con_flag && rdy;
    15     assign  end_rw_cnt = add_rw_cnt && rw_cnt==RW_NUM-1;    
    16 
    17    //写使能 wr_flag和rd_flag由配置表给出
    18     always  @(posedge clk or negedge rst_n)begin
    19         if(rst_n==1'b0)begin
    20             wr_en <= 1'b0;
    21         end
    22         else if(add_rw_cnt && rw_cnt==0 && wr_flag)begin
    23             wr_en <= 1'b1;
    24         end
    25         else begin
    26             wr_en <= 1'b0;
    27         end
    28     end
    29 
    30    //读使能
    31     always  @(posedge clk or negedge rst_n)begin
    32         if(rst_n==1'b0)begin
    33             rd_en <= 1'b0;
    34         end
    35         else if(add_rw_cnt && rw_cnt==1 && rd_flag)begin
    36             rd_en <= 1'b1;
    37         end
    38         else begin
    39             rd_en <= 1'b0;
    40         end
    41     end

     衔接模块中:

     1     //空闲输出
     2     always@(*)begin
     3         if(rd_en || wr_en || rd_com || wr_com)
     4             rdy <= 0;
     5         else 
     6             rdy <= 1;
     7     end
     8     
     9     //命令区间标志位 表示正在响应该命令  状态机实现时序接口模块情况
    10     always@(posedge clk or negedge rst_n)begin
    11         if(!rst_n)
    12             wr_com <= 0;
    13         else if(wr_en)
    14             wr_com <= 1;
    15         else if(wr_com && stop2idle)
    16             wr_com <= 0;
    17     end    
    18     
    19     always@(posedge clk or negedge rst_n)begin
    20         if(!rst_n)
    21             rd_com <= 0;
    22         else if(rd_en)
    23             rd_com <= 1;
    24         else if(rd_com && stop2idle)
    25             rd_com <= 0;
    26     end    
    27     
    28     //地址更新
    29     always@(posedge clk or negedge rst_n)begin
    30         if(!rst_n)
    31             addr_tmp <= 0;
    32         else if(wr_en || rd_en)
    33             addr_tmp <= addr;
    34     end

       到此,寄存器自动化配置中两个重点问题已然解决。本文是我在设计摄像头图像采集和以太网两个案例过程中总结所得。本人认为这种设计思想非常具有通用性,并不仅仅局限于这两个案例,因此单独提出,以备今后回顾和重用。

  • 相关阅读:
    跳台阶问题
    腾讯,百度,网易游戏,华为笔面经验
    进程、线程、应用程序之间的关系
    const用法小结
    vc快捷键
    文献阅读以及如何管理
    数据类型转换
    vc Debug Release
    如何阅读文献
    如何提高表达能力
  • 原文地址:https://www.cnblogs.com/moluoqishi/p/7520494.html
Copyright © 2020-2023  润新知