DMA地址配置及实现
一、DMA配置状态
DMA(Direct Memory Access)为数字系统中用来快速做存储数据交换的功能单元。DMA 传 输 过 程 中 ,当DMA_busy=1时 , 无 法 接 受 新 的 配 置 。 地 址 计 数 传 输 完 所 有 数 据 后,DMA_busy=0;当DMA_busy=0时可以进行新的配置
DMA_op=00 配置起始地址及DMA传输个数, cfg_en有效
DMA_op=01 配置地址跳转步长 cfg_en有效
DMA_op=10 顺序传输,地址+1
DMA_op=11 二维传输 地址+步长
对应跳转条件,加入一个起始状态总共五个状态
二、设计实现
整个传输过程可通过状态机实现,整个过程分为五个状态IDLE,CFG0,CFG1,TRANS0,TRANS1。通过执行DMA_op来进行状态间跳转,IDLE为起始状态,CFG0时配置起始地址及DMA传输个数,CFG1时配置地址跳转步长,在TRANS0状态下,配置地址每次+1,直到传输完所有数,TRANS1状态下配置传输为地址+步长,并据此传输完所有数。通过case实现状态机,并根据不同状态完成地址步长及传输配置。
三、代码实现
//-------------------------
//File Name:DMA_addr.v
//Designer:Liang Genyuan
//Date:2021.08.21
//-------------------------
module DMAaddr(
clk,
rst_n,
cfg_en,
cfg_len,
DMA_busy,
DMA_op,
bgn_addr,
cfg_step
);
input clk;
input rst_n;
input cfg_en;
input [7:0] cfg_len; //初始配置长度
input [15:0]cfg_step; //初始步长
input[1:0]DMA_op;
input [15:0]bgn_addr; // 初始地址
output DMA_busy;
reg DMA_busy;
reg [15:0]DMA_step; //DMA步长
reg [2:0] state_c; //现态
reg [2:0] state_n; //次态
reg [7:0]DMA_len; //DMA长度
reg [15:0]DMA_fin_addr; // DMA配置地址
reg trans_done;
parameter IDLE=3'b000;
parameter CFG0=3'b001;
parameter CFG1=3'b010;
parameter TRANS0=3'b011;
parameter TRANS1=3'b100;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
state_c<=IDLE;
else
state_c<=state_n;
end
always@(*)begin
case(state_c)
IDLE:begin
if((DMA_busy==0)&&(cfg_en==1)&&(DMA_op[1:0]==2'b00))
state_n=CFG0;
else if((DMA_busy==0)&&(cfg_en==1)&&(DMA_op[1:0]==2'b01))
state_n=CFG1;
else if((DMA_busy==0)&&(cfg_en==1)&&(DMA_op[1:0]==2'b10))
state_n=TRANS0;
else if((DMA_busy==0)&&(cfg_en==1)&&(DMA_op[1:0]==2'b10))
state_n=TRANS1;
else
state_n=IDLE;
end
CFG0:begin
state_n=IDLE;
end
CFG1:begin
state_n=IDLE;
end
TRANS0:begin
if(DMA_busy&&trans_done)
state_n=IDLE;
else
state_n=TRANS0;
end
TRANS1:begin
if(DMA_busy&&trans_done)
state_n=IDLE;
else
state_n=TRANS1;
end
default:state_n=IDLE;
endcase
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
DMA_step<=1;
DMA_len<=0;
trans_done<=0;
end
case(state_c)
CFG0:begin
DMA_fin_addr<=bgn_addr;
DMA_len<=cfg_len;
trans_done<=0;
end
CFG1:begin
DMA_step<=cfg_step;
trans_done<=0;
end
TRANS0:begin
DMA_fin_addr<=DMA_fin_addr+1;
DMA_len<=DMA_len-1;
trans_done<=(DMA_len=='d1);
end
TRANS1:begin
DMA_fin_addr<=DMA_fin_addr+DMA_step;
DMA_len<=DMA_len-1;
trans_done<=(DMA_len=='d1);
end
endcase
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
DMA_busy<=0;
else if(DMA_busy&&cfg_en&&DMA_op[1])
DMA_busy<=1;
else if(trans_done)
DMA_busy<=0;
end
endmodule