上一讲我们完成了读的控制,但是并不知道是否设计成功,必须读写结合才行。DDR3 的 app 端的命令总线是读写复用的,因此可能会存在读写冲突的时刻,为了解决此问题,必须进行分时读写,也就是我们说的仲裁,具体是完成读还是写,交由仲裁模块来决定。

一、仲裁模块分析

  在我们实现了 DDR3 控制器 IP 核的读、写之后会发现读和写是共用一组命令线的,因此读、写需要分时的使用 IP 核中的命令总线,具体的解决方法如图:
DDR3(5):读写仲裁-LMLPHP
  如上图所示,我们可以对分时的将 wr_ctrl 和 rd_ctrl 模块的 app_cmd信号传输给 IP 核的 app_cmd 信号。对于 wr_ctrl 和 rd_ctrl 模块的 app_addr信号,我们可以在不使用时将其置为 0,这样我们将 wr_ctrl 和 rd_ctrl 模块的 app_addr 进行按位或,结果即为 IP 核的 app_addr。同理,IP 核的 app_en 也可以通过 wr_ctrl 和 rd_ctrl 模块的 app_en 按位或得到。具体的示例代码如下所示:
assign app_en   = app_wr_en   | app_rd_en;
assign app_addr = app_wr_addr | app_rd_addr;
assign app_cmd = app_wr_en ? app_wr_cmd : app_rd_cmd; //写优先

  如上所述,我们完成了读、写模块与 IP 核的交互,但是假如读、写的启动信号同时产生,将会造成 app_addr 和 app_en 同时有效,上述的按位或的方式将会失效,因此我们不能让读、写启动信号同时产生,为了解决这个问题,我们可以加一个仲裁器来控制产生读、写的启动信号,具体框图如下所示:

DDR3(5):读写仲裁-LMLPHP
  为了完成上图所示的仲裁器,我们可以设定一个状态机,具体如图 8 所示。当复位结束后,可以直接进入到仲裁状态(ARBIT),在 ARBIT 状态等待读、写请求,当某一个请求到来,即进入到对应的状态执行相应的操作,执行完回到ARBIT 状态等待下一次的请求,并且只有在 ARBIT 状态时读、写的请求才会有效,这样就可以保证读、写不会冲突。
DDR3(5):读写仲裁-LMLPHP
 
二、仲裁模块设计
  本次设计仲裁模块,结合上述所说,波形如下所示,写请求优先级高于读优先级。
DDR3(5):读写仲裁-LMLPHP
  本次设计均学自《威三学院FPGA教程》,具体代码就不贴了。
  顶层文件不要忘了例化此模块,同时由于顶层模块多了读写控制的代码:
assign app_en   = app_wr_en   | app_rd_en;
assign app_addr = app_wr_addr | app_rd_addr;
assign app_cmd = app_wr_en ? app_wr_cmd : app_rd_cmd; //写优先

因此在写控制模块和读控制模块的例化中,app_en、app_addr、app_cmd 这三个信号需要修改为对应的信号。

 
三、仲裁模块仿真

DDR3(5):读写仲裁-LMLPHP

DDR3(5):读写仲裁-LMLPHP

  设计仿真时我设计了一个校验程序,如果成功会显示 checked success,失败会显示 error cnt。经过仔细检查发现成功读回了写入的64个128bit数据,打印信息也显示 checked success! 说明此次仲裁模块及之前的读写模块都是正确的。

参考资料:威三学院FPGA教程
05-25 22:02