(原创)Avalon master接口的简易写法(基于Avalon总线的简易dma的实现)

参照张老师的一个例程,练习了下写Avalon master。整个例子有3个接口,一个从端口,两个主端口。其中两个主端口一个用于读,另一个用于写。从端口对整个模块进行控制。整个模块实现了一个简易dma的功能(不带fifo)。主要的控制信号有源地址S_addr,目的地址D_addr,以及数据搬运的长度Longth。

代码
`include "sdram_master_defines.v"
/*
hl.ren.pub@gmail.com
*/


module sdram_master(
    
// signals to connect to an Avalon clock source interface
    clk,
    reset,
    
    
// signals to connect to an Avalon-MM slave interface
    avs_s1_chipselect,
    avs_s1_address,
    avs_s1_read,
    avs_s1_write,
    avs_s1_readdata,
    avs_s1_writedata,
    avs_s1_byteenable,
    avs_s1_waitrequest,

    
// read master port interface
    avm_read_address,
    avm_read_read,
    
//avm_read_byteenable,
    avm_read_readdata,
    avm_read_waitrequest,
    
    
// write master port interface
    avm_write_address,
    avm_write_write,
    
//avm_write_byteenable,
    avm_write_writedata,
    avm_write_waitrequest

    );
    
input    clk;
input     reset;
input     avs_s1_chipselect;
input     [2:0]     avs_s1_address;
input     avs_s1_read;
output     reg [31:0]     avs_s1_readdata;
input     avs_s1_write;
input     [31:0]     avs_s1_writedata;
input     [3:0]     avs_s1_byteenable;
output    avs_s1_waitrequest;

    
// read master port interface
output    reg    [31:0]    avm_read_address;
output    reg    avm_read_read;
//output    reg    [3:0]    avm_read_byteenable;
//input    [31:0]    avm_read_readdata;
input    [15:0]    avm_read_readdata;
input    avm_read_waitrequest;
    
    
// write master port interface
output    reg    [31:0]    avm_write_address;
output    reg    avm_write_write;
//output    reg    [3:0]    avm_write_byteenable;
//output    reg    [31:0]    avm_write_writedata;
output    reg    [15:0]    avm_write_writedata;
input    avm_write_waitrequest;

reg    [31:0]    S_addr;//source address
reg    [31:0]    D_addr;//destination  address
reg    [31:0]    Longth;

reg    Status;

//reg     [31:0]     DMA_DATA;
reg     [15:0]     DMA_DATA;

reg     [31:0]    DMA_Cont;

reg    avs_s1_read_last;
always@(posedge clk)
begin
    avs_s1_read_last 
<= avs_s1_read;
end

wire    avs_s1_waitrequest;
assign    avs_s1_waitrequest = ~(avs_s1_read_last | avs_s1_write);

//read and write regs
always@(posedge clk or posedge reset)
begin
        
if(reset) begin
            S_addr         
<= 32'h0;    
            D_addr         <= 32'h0;    
            Longth         <= 32'h0;
        end
        
else     begin
            
if((avs_s1_chipselect==1'b1) && (avs_s1_write==1'b1)) begin
                
case(avs_s1_address)
                    `S_ADDR:            S_addr         
<= avs_s1_writedata;
                    `D_ADDR:            D_addr         
<= avs_s1_writedata;
                    `LONGTH:            Longth         
<= avs_s1_writedata;
                
endcase
            
end
            
else    begin
                
if((avs_s1_chipselect==1'b1) && (avs_s1_read==1'b1)) begin
                    
case(avs_s1_address)
                        `S_ADDR:            avs_s1_readdata 
<= S_addr;
                        `D_ADDR:            avs_s1_readdata 
<= D_addr;
                        `LONGTH:            avs_s1_readdata 
<= Longth;
                        `STATUS_ADDR:    avs_s1_readdata 
<= {31'h0,Status};
                        default:             avs_s1_readdata <= 32'h0;
                    endcase
                
end
            
end
        
end
end


//start signal
reg    start;
always@(posedge clk or posedge reset)
begin
    
if(reset)
        start         
<= 1'b0;
    else     if((avs_s1_chipselect==1'b1) & (avs_s1_write==1'b1) & (avs_s1_address == `START_ADDR))    
                start     
<= 1'b1;
            else start     <= 1'b0;
end

//status signal
reg    done;
reg done_last;
always@(posedge clk)
begin
    
if(reset)     done_last         <= 1'b0;
    else         done_last         <= done;
end


always@(posedge clk)
begin
    
if(reset)
    
begin
        Status 
<= 1'b0;
    end
    
else     if((avs_s1_chipselect==1'b1) &  (avs_s1_write==1'b1)  & (avs_s1_address == `START_ADDR) )    
            
begin
                Status 
<= 1'b0;
            end
            
else     if( (done_last == 1'b0 )&( done == 1'b1) )
                    
begin
                        Status 
<= 1'b1;
                    end
end

//FSM

reg    [5:0]    DMA_state;

parameter    DMA_IDLE                =    0;
parameter    READ                    =    1;
parameter    WAIT_READ                =    2;
parameter    WRITE                =    3;
parameter    WAIT_WRITE            =    4;
parameter    CALC_NEXT                =    5;
parameter    DMA_DONE                =    6;

always@(posedge clk)
begin
    
if(reset) begin
        DMA_state 
<= DMA_IDLE;
        DMA_Cont     
<= 32'h0;
    end
    
else begin
        
case(DMA_state)
            DMA_IDLE: 
begin
                DMA_Cont 
<= 32'h0;
                done                 <= 1'b0;
                if(start) 
                    DMA_state         
<= READ;
            
end
            READ: 
begin
                avm_read_address 
<= S_addr + DMA_Cont;
                
//avm_read_byteenable <= 4'b0001; 
                avm_read_read <= 1'b1;
                DMA_state    <= WAIT_READ;
            
end
            WAIT_READ: 
begin
                
if(avm_read_waitrequest == 1'b0 )
                begin
                    avm_read_read 
<= 1'b0;
                    DMA_DATA <= avm_read_readdata;
                    DMA_state 
<= WRITE;
                
end
            
end
            WRITE: 
begin
                avm_write_address 
<= D_addr + DMA_Cont;
                
//avm_write_byteenable <= 4'b0001;
                avm_write_write <= 1'b1;
                avm_write_writedata <= DMA_DATA;
                
//avm_write_writedata <= DMA_Cont;//temp test
                DMA_state <= WAIT_WRITE;
            
end
            WAIT_WRITE: 
begin
                
if(avm_write_waitrequest == 1'b0 )
                    begin
                        DMA_Cont 
<= DMA_Cont + 32'h2;
                        //avm_write_address <= 0;
                        avm_write_write <= 1'b0;
                        if(DMA_Cont < Longth)
                            DMA_state 
<= READ;
                        
else
                            DMA_state 
<= DMA_DONE;
                            
                    
end
            
end
            DMA_DONE: 
begin
                done 
<= 1'b1;
                DMA_state <= DMA_IDLE;
            
end
            
defaultbegin
                DMA_state 
<= DMA_IDLE;
            
end            
        
endcase
    
end
end
endmodule

 

 整个运行过程由一个状态机DMA_state来控制。sdram_master_defines.v定义了一些从端口的地址。

 编写段简易的程序来驱动和验证这个simple-dma。

 代码

/*
 * "Hello World" example.
 *
 * This example prints 'Hello from Nios II' to the STDOUT stream. It runs on
 * the Nios II 'standard', 'full_featured', 'fast', and 'low_cost' example
 * designs. It runs with or without the MicroC/OS-II RTOS and requires a STDOUT
 * device in your system's hardware.
 * The memory footprint of this hosted application is ~69 kbytes by default
 * using the standard reference design.
 *
 * For a reduced footprint version of this template, and an explanation of how
 * to reduce the memory footprint for a given application, see the
 * "small_hello_world" template.
 *
 
*/
#include 
<stdio.h>
#include 
"sdram_master.h"
#include 
"system.h"
#include 
"io.h"

int main()
{
    unsigned 
char i,j;
    
int temp;
    
for(i=0;i<100;i++)
        IOWR_8DIRECT(SDRAM_U1_BASE,i,i);
    
    IOWR(SDRAM_MASTER_INST_BASE,S_ADDR,SDRAM_U1_BASE);
    IOWR(SDRAM_MASTER_INST_BASE,D_ADDR,SDRAM_U2_BASE);
    IOWR(SDRAM_MASTER_INST_BASE,LONGTH,
100);
    IOWR(SDRAM_MASTER_INST_BASE,START_ADDR,
1);
    
    temp
=IORD(SDRAM_MASTER_INST_BASE,S_ADDR);
    printf(
"S_ADDR:w,r==%d,%d\n",SDRAM_U1_BASE,temp);
    temp
=IORD(SDRAM_MASTER_INST_BASE,D_ADDR);
    printf(
"D_ADDR:w,r==%d,%d\n",SDRAM_U2_BASE,temp);    
    temp
=IORD(SDRAM_MASTER_INST_BASE,LONGTH);
    printf(
"LONGTH:w,r==%d,%d\n",100,temp);    
    
    
while(IORD(SDRAM_MASTER_INST_BASE,STATUS_ADDR)!=1){
    printf(
"waiting...!\n");
    
//break;
    };
    
    
for(i=0;i<100;i++){
        j
=IORD_8DIRECT(SDRAM_U1_BASE,i);
        printf(
"SDRAM_U1:i,j == %d, %d\n",i,j);
    }
    
for(i=0;i<100;i++){
        j
=IORD_8DIRECT(SDRAM_U2_BASE,i);
        printf(
"SDRAM_U2:i,j == %d, %d\n",i,j);
    }    
        
    
  printf(
"Hello from Nios II!\n");

  
return 0;
}

 

 运行结果和设想的一样,没有错误。

本文中所设计模块的全部代码可以以下方式取得(linux下需安装git,windows下可安装msysgit):

git clone git://github.com/orlunix/simple-dma.git 

posted @ 2010-08-28 02:58  任怀鲁  阅读(4231)  评论(2编辑  收藏  举报