|
发表于 2013-3-29 13:24:55
|
显示全部楼层
本帖最后由 loywong 于 2013-3-29 13:26 编辑
你用nios2吗?如果用需要sg-dma和一个stream的wrapper,这个我有做过的现成代码给你参考:
比较久远了,有些参数你自己看看。
先做一个fft,再用这个wrapper调用它:
module fft_avalon_wraper
(
input clk,
input reset_n,
input mm_address,
input mm_read,
output [7 : 0] mm_readdate,
input mm_write,
input [7 : 0] mm_writedate,
output sink_ready,
input sink_valid,
input sink_sop,
input sink_eop,
input [WIDTH * 2 - 1 : 0] sink_data,
input [1 : 0] sink_empty,
input [1 : 0] sink_error,
input source_ready,
output source_valid,
output source_sop,
output source_eop,
output [WIDTH * 2 - 1 : 0] source_data,
output [1 : 0] source_empty,
output [1 : 0] source_error
);
parameter WIDTH = 16;
reg inverse;
reg [5 : 0] exponent;
wire [5 : 0] source_exp;
assign mm_readdate = (mm_address == 1'b0) ? {exponent[5], exponent[5] ,exponent} : {7'b0, inverse};
assign source_empty = 2'b0;
always@(posedge clk)
begin
if(~reset_n)
begin
inverse <= 1'b0;
exponent <= 6'b0;
end
else
begin
if(mm_write)
begin
inverse <= mm_writedate[0];
end
if(source_sop)
begin
exponent <= source_exp;
end
end
end
wire [WIDTH * 2 - 1 : 0] sink_data_xe;
wire [WIDTH * 2 - 1 : 0] source_data_xe;
localparam W = WIDTH * 2;
genvar i;
generate
for(i = 0; i < W; i = i + 8)
begin :xe_byte
assign sink_data_xe[i + 7 : i] = sink_data[W - 1 - i : W - 8 - i];
assign source_data[i + 7 : i] = source_data_xe[W - 1 - i : W - 8 - i];
end
endgenerate
fft thefft
(
clk,
reset_n,
inverse,
sink_valid,
sink_sop,
sink_eop,
sink_data_xe[WIDTH - 1 : 0],
sink_data_xe[WIDTH * 2 - 1 : WIDTH],
sink_error,
source_ready,
sink_ready,
source_error,
source_sop,
source_eop,
source_valid,
source_exp,
source_data_xe[WIDTH - 1 : 0],
source_data_xe[WIDTH * 2 - 1 : WIDTH]
);
endmodule
然后做成一个memory map的slave外设,它有两个地址,地址0读出exp,地址1读出 是FFT或是IFFT变换,任何地址写0,表示做FFT,写1表示做IFFT。
sopc builder中做两个sg-dma,一个用于给fft送数据,另一个收fft数据。
软件:
#include <system.h>
#include <stdio.h>
#include <stdlib.h>
#include <altera_avalon_sgdma.h>
#include <altera_avalon_sgdma_regs.h>
#include <altera_avalon_sgdma_descriptor.h>
#include <altera_avalon_performance_counter.h>
#include "sys/alt_cache.h"
#include "sys/alt_sys_wrappers.h"
#define FFT_LEN 1024
alt_sgdma_dev *pPreFftDma;
alt_sgdma_descriptor *pPreFftDmaDescrs;
alt_sgdma_dev *pPostFftDma;
alt_sgdma_descriptor *pPostFftDmaDescrs;
#pragma pack(1)
typedef struct __ShortCplx
{
alt_16 Real;
alt_16 Imag;
} ShortCplx;
ShortCplx X[FFT_LEN];
ShortCplx F[FFT_LEN];
alt_8 Fexp;
alt_8 FftTransFinished = 0;
alt_8 FftRecvFinished = 0;
void createPreFftDmaDescr()
{
pPreFftDmaDescrs = (alt_sgdma_descriptor *)malloc(2 * sizeof(alt_sgdma_descriptor));
alt_avalon_sgdma_construct_mem_to_stream_desc(
pPreFftDmaDescrs,
pPreFftDmaDescrs + 1,
(alt_u32 *)X,
FFT_LEN * sizeof(ShortCplx),
0,
1,
1,
0);
}
void createPostFftDmaDescr()
{
pPostFftDmaDescrs = (alt_sgdma_descriptor *)malloc(2 * sizeof(alt_sgdma_descriptor));
alt_avalon_sgdma_construct_stream_to_mem_desc(
pPostFftDmaDescrs,
pPostFftDmaDescrs + 1,
(alt_u32 *)F,
0/*FFT_LEN * sizeof(ShortCplx)*/,
0);
}
static void preFftDma_ISR(void *pContext)
{
int i, ctrl;
ctrl = IORD_ALTERA_AVALON_SGDMA_STATUS(pPreFftDma->base);
if(ctrl & ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK)
{
i = 1;
FftTransFinished = 1;
}
}
static void postFftDma_ISR(void *pContext)
{
int i, ctrl;
ctrl = IORD_ALTERA_AVALON_SGDMA_STATUS(pPostFftDma->base);
if(ctrl & ALTERA_AVALON_SGDMA_STATUS_EOP_ENCOUNTERED_MSK)
{
i = 1;
FftRecvFinished = 1;
}
}
int main()
{
alt_u32 control;
int i;
printf("Hello from Nios II!\n");
pPreFftDma = alt_avalon_sgdma_open(SGDMA_PREFFT_NAME);
pPostFftDma = alt_avalon_sgdma_open(SGDMA_POSTFFT_NAME);
alt_avalon_sgdma_register_callback(
pPreFftDma,
preFftDma_ISR,
ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK,
NULL);
alt_avalon_sgdma_register_callback(
pPostFftDma,
postFftDma_ISR,
ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK,
NULL);
createPreFftDmaDescr();
createPostFftDmaDescr();
control = IORD_ALTERA_AVALON_SGDMA_CONTROL(pPreFftDma->base);
control |= ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK;
IOWR_ALTERA_AVALON_SGDMA_CONTROL(pPreFftDma->base, control);
control = IORD_ALTERA_AVALON_SGDMA_CONTROL(pPostFftDma->base);
control |= ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK;
IOWR_ALTERA_AVALON_SGDMA_CONTROL(pPostFftDma->base, control);
for(i = 0; i < FFT_LEN; i++)
{
X.Imag = 0;
if(i < FFT_LEN / 2)
{
X.Real = 32767;
}
else
{
X.Real = -32767;
}
}
alt_dcache_flush((void *)X, FFT_LEN * sizeof(ShortCplx));
PERF_RESET(PFC_BASE);
PERF_START_MEASURING(PFC_BASE);
PERF_BEGIN(PFC_BASE, 1);
alt_avalon_sgdma_do_async_transfer(pPostFftDma, pPostFftDmaDescrs);
alt_avalon_sgdma_do_async_transfer(pPreFftDma, pPreFftDmaDescrs);
while(1)
{
if(FftRecvFinished)
{
PERF_END(PFC_BASE, 1);
FftRecvFinished = 0;
alt_dcache_flush((void *)F, FFT_LEN * sizeof(ShortCplx));
Fexp = IORD(FFT_AVALON_BASE, 0);
PERF_STOP_MEASURING(PFC_BASE);
perf_print_formatted_report((void *)PFC_BASE, alt_get_cpu_freq(), 1, "FFT");
PERF_RESET(PFC_BASE);
PERF_START_MEASURING(PFC_BASE);
alt_avalon_sgdma_do_async_transfer(pPostFftDma, pPostFftDmaDescrs);
alt_avalon_sgdma_do_async_transfer(pPreFftDma, pPreFftDmaDescrs);
PERF_BEGIN(PFC_BASE, 1);
}
}
return 0;
}
当中有大量sg-dma的操作,特别是描述符链表,请到altera.com上搜其user guide并自行理解。
如有那条不明白,上altera.com搜之。如果你没有用sopc系统和nios2软核的经验,可能需要学的还很多。
如果单纯用逻辑写stream if,会稍麻烦,我没做过,不敢妄言。 |
|