(原创)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
default: begin
DMA_state <= DMA_IDLE;
end
endcase
end
end
endmodule
/*
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
default: begin
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;
}
* "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