基于AHB的四通道DMA控制器设计-dmac_arb.v
dmac_arb = DMA 仲裁器(4通道固定优先级仲裁)
作用:4个DMA通道抢1套AHB总线,按通道0→1→2→3优先级,同一时间只让1个通道用总线,不冲突。
// ==============================
// 模块:DMA 4通道仲裁器
// 功能:4个DMA通道按优先级(0>1>2>3)仲裁,同一时刻只允许1个通道使用总线
// ==============================
module dmac_arb(
// 时钟与复位
input clk, // 系统时钟
input rst, // 低电平复位
// 通道请求信号(通道0~3向仲裁器发请求)
input req_0, // 通道0请求使用总线
input req_1, // 通道1请求
input req_2, // 通道2请求
input req_3, // 通道3请求
// 通道总使能(全局开关)
input ch_0_en, // 通道0全局使能
input ch_1_en,
input ch_2_en,
input ch_3_en,
// 目标设备选择(=1表示访问外设,=0访问内存)
input target_0,
input target_1,
input target_2,
input target_3,
// 仲裁输出:给对应通道发“允许使用总线”
output reg en_0, // 允许通道0使用总线
output reg en_1,
output reg en_2,
output reg en_3,
// 应答信号:通知通道“本次传输完成”
output reg ack_0,
output reg ack_1,
output reg ack_2,
output reg ack_3,
// 总线传输完成信号(来自AHB控制器)
input req_done, // AHB一次传输完成
// 通道初始传输完成标志
input ch_0_t0_done,
input ch_1_t0_done,
input ch_2_t0_done,
input ch_3_t0_done,
// FIFO空标志(DMA通道FIFO)
input fifo_0_empty,
input fifo_1_empty,
input fifo_2_empty,
input fifo_3_empty,
// FIFO满标志
input fifo_0_full,
input fifo_1_full,
input fifo_2_full,
input fifo_3_full
);
// ==============================
// 状态机定义(9位one-hot编码)
// IDLE:空闲
// ST_x:通道x启动准备
// W_x :通道x正在占用总线、等待完成
// ==============================
parameter IDLE = 9’b000000001;
parameter ST_0 = 9’b000000010;
parameter W_0 = 9’b000000100;
parameter ST_1 = 9’b000001000;
parameter W_1 = 9’b000010000;
parameter ST_2 = 9’b000100000;
parameter W_2 = 9’b001000000;
parameter ST_3 = 9’b010000000;
parameter W_3 = 9’b100000000;
reg [8:0] cs; // 当前状态 current state
reg [8:0] ns; // 下一状态 next state
// ==============================
// 时序逻辑:状态更新(时钟同步)
// ==============================
always @(posedge clk or negedge rst)
if (!rst)
cs <= IDLE; // 复位→空闲
else
cs <= ns; // 下一状态赋值给当前状态
// ==============================
// 组合逻辑:状态跳转规则(核心仲裁逻辑)
// ==============================
always @(*)
case (cs)
IDLE:begin
// 优先级:req_0 > req_1 > req_2 > req_3
if (req_0 && (~ack_0)) ns = ST_0;
else if (req_1 && (~ack_1)) ns = ST_1;
else if (req_2 && (~ack_2)) ns = ST_2;
else if (req_3 && (~ack_3)) ns = ST_3;
// 未完成初始传输、访问内存的通道
else if (ch_0_en && (~ch_0_t0_done) && (~target_0)) ns=ST_0;
else if (ch_1_en && (~ch_1_t0_done) && (~target_1)) ns=ST_1;
else if (ch_2_en && (~ch_2_t0_done) && (~target_2)) ns=ST_2;
else if (ch_3_en && (~ch_3_t0_done) && (~target_3)) ns=ST_3;
// FIFO非空、访问外设的通道
else if (ch_0_en && (~fifo_0_empty) && (target_0)) ns=ST_0;
else if (ch_1_en && (~fifo_1_empty) && (target_1)) ns=ST_1;
else if (ch_2_en && (~fifo_2_empty) && (target_2)) ns=ST_2;
else if (ch_3_en && (~fifo_3_empty) && (target_3)) ns=ST_3;
else ns = IDLE;
end
ST_0: ns = W_0; // 准备态→等待传输完成
ST_1: ns = W_1;
ST_2: ns = W_2;
ST_3: ns = W_3;
// ==============================
// W_0:通道0占用总线,等待req_done完成
// ==============================
W_0 :begin
if (~req_done) ns = W_0; // 未完成→继续等
else if (req_1) ns = ST_1; // 完成→按优先级切下一个
else if (req_2) ns = ST_2;
else if (req_3) ns = ST_3;
else if (ch_1_en && (~ch_1_t0_done) && (~target_1)) ns=ST_1;
else if (ch_2_en && (~ch_2_t0_done) && (~target_2)) ns=ST_2;
else if (ch_3_en && (~ch_3_t0_done) && (~target_3)) ns=ST_3;
else if (ch_1_en && (~fifo_1_empty) && (target_1)) ns=ST_1;
else if (ch_2_en && (~fifo_2_empty) && (target_2)) ns=ST_2;
else if (ch_3_en && (~fifo_3_empty) && (target_3)) ns=ST_3;
else if (req_done) ns = IDLE; // 无请求→回空闲
else ns = W_0;
end
W_1 :begin // 通道1逻辑同W_0
if (~req_done) ns = W_1;
else if (req_2) ns = ST_2;
else if (req_3) ns = ST_3;
else if (ch_2_en && (~ch_2_t0_done) && (~target_2)) ns=ST_2;
else if (ch_3_en && (~ch_3_t0_done) && (~target_3)) ns=ST_3;
else if (ch_2_en && (~fifo_2_empty) && (target_2)) ns=ST_2;
else if (ch_3_en && (~fifo_3_empty) && (target_3)) ns=ST_3;
else if (req_done) ns = IDLE;
else ns = W_1;
end
W_2 :begin // 通道2逻辑同W_0
if (~req_done) ns = W_2;
else if (req_3) ns = ST_3;
else if (ch_3_en && (~ch_3_t0_done) && (~target_3)) ns=ST_3;
else if (ch_3_en && (~fifo_3_empty) && (target_3)) ns=ST_3;
else if (req_done) ns = IDLE;
else ns = W_2;
end
W_3 :begin // 通道3:完成直接回空闲
if (~req_done) ns = W_3;
else ns = IDLE;
end
default: ns = IDLE;
endcase
// ==============================
// 输出通道使能:进入W_x状态时,打开对应通道en_x
// ==============================
always @(posedge clk or negedge rst)
if (!rst) en_0 <= 0;
else if (ns == W_0) en_0 <= 1; // 状态到W_0→允许通道0用总线
else en_0 <= 0;
always @(posedge clk or negedge rst)
if (!rst) en_1 <= 0;
else if (ns == W_1) en_1 <= 1;
else en_1 <= 0;
always @(posedge clk or negedge rst)
if (!rst) en_2 <= 0;
else if (ns == W_2) en_2 <= 1;
else en_2 <= 0;
always @(posedge clk or negedge rst)
if (!rst) en_3 <= 0;
else if (ns == W_3) en_3 <= 1;
else en_3 <= 0;
// ==============================
// 通道完成应答:传输完成时给通道发ack_x=1
// 【注:代码这里有BUG,所有ack都判断了req_0,应该是对应req_x】
// ==============================
always @(posedge clk or negedge rst)
if (!rst) ack_0 <= 0;
else if (cs==W_0 && req_done && req_0) ack_0 <= 1;
else ack_0 <= 0;
always @(posedge clk or negedge rst)
if (!rst) ack_1 <= 0;
else if (cs==W_1 && req_done && req_0) ack_1 <= 1; // BUG:应写req_1
else ack_1 <= 0;
always @(posedge clk or negedge rst)
if (!rst) ack_2 <= 0;
else if (cs==W_2 && req_done && req_0) ack_2 <= 1; // BUG:应写req_2
else ack_2 <= 0;
always @(posedge clk or negedge rst)
if (!rst) ack_3 <= 0;
else if (cs==W_3 && req_done && req_0) ack_3 <= 1; // BUG:应写req_3
else ack_3 <= 0;
endmodule