天天看點

NIOS2随筆——自定義IP(DPRAM)

AVALON總線分類

在QSYS下,一個簡單的元件包含了許多接口,它們實作了不同的功能,大緻有下面幾種:

Avalon-MM

Avalon-ST

Avalon Conduit

Avalon-TC

Avalon Interrupt

Avalon Clock.

這些标準是開源的,不需要license就可以開發使用。下圖是一個總線應用的示意圖:

<a href="http://s3.51cto.com/wyfs02/M00/86/15/wKioL1e0Gm3izts1AADLRaaI9b4776.jpg" target="_blank"></a>

2. AVALON MM總線

這裡以AVALON MM為例,設計一個使用者自定義的DPRAM元件,并用DMA方式将DPRAM PORTB中的資料搬移到記憶體SDRAM/DDR2中。下面接口定義是AVALON MM SLAVE總線的信号,具體時序在Avalon Interface Specifications中有較長的描述。

<code>//avalon MM slave</code>

<code>input avs_clk,</code>

<code>input avs_reset_n,</code>

<code>input avs_chipselect_n,</code>

<code>input [7:0] avs_address,</code>

<code>input [3:0] avs_byteenable,</code>

<code>input avs_write,</code>

<code>input [31 :0] avs_writedata,</code>

<code>input avs_read,</code>

<code>output avs_readdatavalid,</code>

<code>output [31 :0] avs_readdata</code>

3. Qsys中添加自定義元件

1) 建立元件

<a href="http://s3.51cto.com/wyfs02/M01/86/15/wKioL1e0HgKxVwZ9AAB_gS4gy2M556.jpg" target="_blank"></a>

2)添加檔案

<a href="http://s4.51cto.com/wyfs02/M01/86/15/wKioL1e0HmrjMx98AACHdhdzvHY121.jpg" target="_blank"></a>

3) 信号設定

<a href="http://s3.51cto.com/wyfs02/M01/86/15/wKiom1e0Hu7iMPy7AAC72yJKk4w782.jpg" target="_blank"></a>

4) 接口時序

<a href="http://s1.51cto.com/wyfs02/M02/86/15/wKioL1e0H2yzN8TvAACgJ_Ytcdw970.jpg" target="_blank"></a>

4. FPGA邏輯代碼

下面是使用者自定義的DPRAM的Verilog代碼:

<code>//file name:       vid_dpram.v</code>

<code>//author:           shugen.yin</code>

<code>//date:             2016.8.15</code>

<code>//function:         user dpram for Qsys</code>

<code>//log: </code>

<code>module vid_dpram(</code>

<code>    </code><code>//user port</code>

<code>    </code><code>input inclock,</code>

<code>    </code><code>input [7:0] data,</code>

<code>    </code><code>input data_valid,</code>

<code>    </code><code>input vid_vsync,</code>

<code>    </code> 

<code>    </code><code>//avalon MM slave</code>

<code>    </code><code>input avs_clk,</code>

<code>    </code><code>input avs_reset_n,</code>

<code>    </code><code>input avs_chipselect_n,</code>

<code>    </code><code>input [7:0] avs_address,</code>

<code>    </code><code>input [3:0] avs_byteenable,</code>

<code>    </code><code>input avs_write,</code>

<code>    </code><code>input [31 :0] avs_writedata,</code>

<code>    </code><code>input avs_read,</code>

<code>    </code><code>output avs_readdatavalid,</code>

<code>    </code><code>output [31 :0] avs_readdata</code>

<code>);</code>

<code>parameter VID_WIDTH = 640;</code>

<code>reg avs_readdatavalid_r0;</code>

<code>reg avs_readdatavalid_r1;</code>

<code>reg [9:0] wraddress_0;</code>

<code>reg [9:0] wraddress_1;</code>

<code>reg rdaddress_high_bit;</code>

<code>reg wraddress_high_bit;</code>

<code>wire [10:0] wraddress;</code>

<code>wire [8:0] rdaddress;</code>

<code>assign rdaddress = (avs_chipselect_n==1</code><code>'b0)?{1'</code><code>b0,avs_address[7:0]}:0;</code>

<code>wire rden;</code>

<code>assign rden = avs_read &amp; ~avs_chipselect_n;   </code>

<code>dpram_01    dpram_01_inst (</code>

<code>    </code><code>.data ( data ),</code>

<code>    </code><code>.wrclock ( inclock ),</code>

<code>    </code><code>.rdclock ( avs_clk ),</code>

<code>    </code><code>.rden   (rden),</code>

<code>    </code><code>.rdaddress ( rdaddress ),        </code><code>//input [8:0]  rdaddress;</code>

<code>    </code><code>.wraddress ( wraddress ),        </code><code>//input [10:0]  wraddress;</code>

<code>    </code><code>.wren (1'b0 ),</code>

<code>    </code><code>.q ( avs_readdata )</code>

<code>    </code><code>);</code>

<code>endmodule</code>

dpram的PORT B端用HEX檔案初始化(511~0循環遞減):

<a href="http://s1.51cto.com/wyfs02/M01/86/15/wKioL1e0I2qxQE2bAABXOWoPIyQ715.jpg" target="_blank"></a>

5. NIOS2 源代碼

<code>#include &lt;stdio.h&gt;</code>

<code>#include &lt;sys/unistd.h&gt;</code>

<code>#include &lt;string.h&gt;</code>

<code>#include &lt;sys/alt_irq.h&gt;</code>

<code>#include "system.h"</code>

<code>#include "alt_types.h"</code>

<code>#include "altera_avalon_dma_regs.h"</code>

<code>#include "sys/alt_dma.h"</code>

<code>#include &lt;sys/alt_cache.h&gt;</code>

<code>#define DAT_LEN 640</code>

<code>unsigned </code><code>int</code> <code>buffer0[DAT_LEN/4];</code>

<code>unsigned </code><code>int</code> <code>*point=VID_DPRAM_0_BASE;</code>

<code>static</code> <code>void</code> <code>DMA_Init(</code><code>void</code><code>); </code><code>//初始化DMA</code>

<code>unsigned </code><code>int</code> <code>dma_end_flag = 0;</code>

<code>alt_dma_txchan tx;</code>

<code>alt_dma_rxchan rx;</code>

<code>void</code> <code>dma_done()</code>

<code>{</code>

<code>    </code><code>dma_end_flag++;</code>

<code>}</code>

<code>static</code> <code>void</code> <code>DMA_Init(</code><code>void</code><code>)</code>

<code>    </code><code>tx = alt_dma_txchan_open(</code><code>"/dev/dma_0"</code><code>);</code>

<code>    </code><code>if</code><code>(tx != NULL)</code>

<code>    </code><code>{</code>

<code>        </code><code>printf</code><code>(</code><code>"DMA transition start\n"</code><code>);</code>

<code>    </code><code>}</code>

<code>    </code><code>alt_dma_txchan_ioctl(tx,ALT_DMA_SET_MODE_32,NULL);</code>

<code>    </code><code>//point是源位址、傳輸資料塊長度是DAT_LEN</code>

<code>    </code><code>alt_dma_txchan_send(tx, point, DAT_LEN, NULL, NULL);</code>

<code>    </code><code>rx = alt_dma_rxchan_open(</code><code>"/dev/dma_0"</code><code>);</code>

<code>    </code><code>alt_dma_rxchan_ioctl(rx,ALT_DMA_SET_MODE_32,NULL);</code>

<code>    </code><code>//buffer0是目标位址、傳輸資料塊長度是DAT_LEN、dma_done()是DMA完成後被調用的回調函數</code>

<code>    </code><code>alt_dma_rxchan_prepare(rx, buffer0 , DAT_LEN, dma_done, NULL);</code>

<code>int</code> <code>main()</code>

<code>    </code><code>int</code> <code>i;</code>

<code>    </code><code>for</code><code>(i=0;i&lt;DAT_LEN/4;i++)</code>

<code>        </code><code>buffer0[i] = 0;</code>

<code>//  alt_dcache_flush_all(); //if the nios2 core uses the cache</code>

<code>    </code><code>DMA_Init();</code>

<code>    </code><code>//等待中斷結束,說明傳輸完成</code>

<code>    </code><code>while</code><code>(dma_end_flag == 0);</code>

<code>    </code><code>alt_dma_txchan_close(tx);</code>

<code>    </code><code>alt_dma_rxchan_close(rx);</code>

<code>    </code><code>printf</code><code>(</code><code>"\n============start===========\n"</code><code>);</code>

<code>    </code><code>//列印接收位址的資料</code>

<code>        </code><code>printf</code><code>(</code><code>"buffer0[%d]=%d\t"</code><code>,i,buffer0[i]);</code>

<code>    </code><code>printf</code><code>(</code><code>"\n=============end===========\n"</code><code>);</code>

<code>    </code><code>return</code> <code>0;</code>

6. 運作結果

<a href="http://s2.51cto.com/wyfs02/M00/86/16/wKiom1e0JHHSssrhAADYzcNDodA880.jpg" target="_blank"></a>

本文轉自 shugenyin 51CTO部落格,原文連結:http://blog.51cto.com/shugenyin/1839613