基于AHB的四通道DMA控制器设计-dmac_intf.v

`timescale 1ns / 10ps

// ==============================
// 模块:DMA 配置接口(AHB 从机)
// 功能:CPU 通过 AHB 配置 DMA 4 通道
// ==============================
module dmac_intf(
// AHB 从机信号(CPU ↔ DMA)
input HCLK , // AHB 时钟
input HRESETn , // 低电平复位
input HSEL , // 选中 DMA 模块
input HREADY , // 从机就绪(hreadyin)
input[1:0] HTRANS , // 传输类型
input[2:0] HSIZE , // 传输位宽
input HWRITE , // 1=写 0=读
input[31:0] HADDR , // 地址
input[31:0] HWDATA , // 写数据(CPU→DMA)
output HREADYOUT , // DMA 给 CPU 的就绪信号
output HRESP , // 响应信号(固定OK)
output reg [31:0] HRDATA , // 读数据(DMA→CPU)

// 输出给 DMA 内核(仲裁/传输模块)
output ch_0_en , // 通道0使能
output ch_0_target , // 通道0方向(0:存→外设 1:外设→存)
output[9: 0] ch_0_size , // 通道0传输长度
output ch_1_en ,
output ch_1_target ,
output[9: 0] ch_1_size ,
output ch_2_en ,
output ch_2_target ,
output[9: 0] ch_2_size ,
output ch_3_en ,
output ch_3_target ,
output[9: 0] ch_3_size ,

// 源/目标地址(给DMA传输用)
output reg [31:0] ch_0_sour , // 通道0源地址
output reg [31:0] ch_0_dest , // 通道0目标地址
output reg [31:0] ch_1_sour ,
output reg [31:0] ch_1_dest ,
output reg [31:0] ch_2_sour ,
output reg [31:0] ch_2_dest ,
output reg [31:0] ch_3_sour ,
output reg [31:0] ch_3_dest
);

// ==============================
// 基地址:CPU 访问 DMA 寄存器的起始地址
// ==============================
parameter BASE_ADDR = 32’h40000000;

// ==============================
// 内部控制信号
// ==============================
wire ahb_access ; // AHB有效访问
wire ahb_read ; // AHB读
reg ahb_write ; // AHB写(打拍)
reg [31:0] haddr_d ; // 地址打拍

// 4个通道的控制寄存器
reg [31:0] ch_0_ctrl ;
reg [31:0] ch_1_ctrl ;
reg [31:0] ch_2_ctrl ;
reg [31:0] ch_3_ctrl ;

// 写使能信号(地址译码)
wire ch_0_ctrl_wr ; // 通道0控制寄存器写
wire ch_0_sour_wr ; // 通道0源地址写
wire ch_0_dest_wr ; // 通道0目标地址写
wire ch_1_ctrl_wr ;
wire ch_1_sour_wr ;
wire ch_1_dest_wr ;
wire ch_2_ctrl_wr ;
wire ch_2_sour_wr ;
wire ch_2_dest_wr ;
wire ch_3_ctrl_wr ;
wire ch_3_sour_wr ;
wire ch_3_dest_wr ;

// ==============================
// AHB 访问控制逻辑
// ==============================
// 有效访问:非空闲传输 + 被选中 + 就绪
assign ahb_access = HTRANS[1] & HSEL & HREADY ;

// AHB 读
assign ahb_read = ahb_access & (~HWRITE ) ;

// AHB 写(打一拍,对齐时序)
always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ahb_write <= 1’b0;
else
ahb_write <= ahb_access & HWRITE ;
end

// 地址锁存:写的时候把地址存下来
always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
haddr_d <= 32’h0 ;
else if(ahb_access & HWRITE)
haddr_d <= HADDR ;
end

// ==============================
// 地址译码:根据地址产生对应寄存器写使能
// 基地址 + 偏移 → 选中哪个寄存器
// ==============================
assign ch_0_ctrl_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+0); // 0x00
assign ch_0_sour_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+4); // 0x04
assign ch_0_dest_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+8); // 0x08

assign ch_1_ctrl_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+12); // 0x0C
assign ch_1_sour_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+16); // 0x10
assign ch_1_dest_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+20); // 0x14

assign ch_2_ctrl_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+24); // 0x18
assign ch_2_sour_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+28); // 0x1C
assign ch_2_dest_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+32); // 0x20

assign ch_3_ctrl_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+36); // 0x24
assign ch_3_sour_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+40); // 0x28
assign ch_3_dest_wr = (ahb_write==1’b1)&&(haddr_d==BASE_ADDR+44); // 0x2C

// ==============================
// 写寄存器:CPU 写控制/地址
// ==============================
// 通道0控制寄存器
always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_0_ctrl<=32’h0;
else if(ch_0_ctrl_wr)
ch_0_ctrl<= HWDATA;
end

// 通道0源地址
always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_0_sour<=32’h0 ;
else if(ch_0_sour_wr)
ch_0_sour<= HWDATA ;
end

// 通道0目标地址
always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_0_dest<=32’h0 ;
else if(ch_0_dest_wr)
ch_0_dest<= HWDATA ;
end

// ——————————
// 通道1/2/3 写逻辑和通道0完全一样
// ——————————
always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_1_ctrl<=32’h0;
else if(ch_1_ctrl_wr)
ch_1_ctrl<= HWDATA;
end

always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_1_sour<=32’h0 ;
else if(ch_1_sour_wr)
ch_1_sour<= HWDATA ;
end

always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_1_dest<=32’h0 ;
else if(ch_1_dest_wr)
ch_1_dest<= HWDATA ;
end

// 通道2、3省略,结构相同
always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_2_ctrl<=32’h0;
else if(ch_2_ctrl_wr)
ch_2_ctrl<=HWDATA;
end

always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_2_sour<=32’h0 ;
else if(ch_2_sour_wr)
ch_2_sour<= HWDATA ;
end

always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_2_dest<=32’h0 ;
else if(ch_2_dest_wr)
ch_2_dest<= HWDATA ;
end

always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_3_ctrl<=32’h0;
else if(ch_3_ctrl_wr)
ch_3_ctrl<= HWDATA;
end

always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_3_sour<=32’h0 ;
else if(ch_3_sour_wr)
ch_3_sour<= HWDATA ;
end

always@(posedge HCLK or negedge HRESETn) begin
if(!HRESETn)
ch_3_dest<=32’h0 ;
else if(ch_3_dest_wr)
ch_3_dest<= HWDATA ;
end

// ==============================
// 控制寄存器位解析(给DMA内核用)
// ==============================
assign ch_0_en = ch_0_ctrl[0] ; // 位0:通道使能
assign ch_0_target = ch_0_ctrl[4] ; // 位4:方向(0=存→外设 1=外设→存)
assign ch_0_size = ch_0_ctrl[17:8] ; // 位[17:8]:传输长度

assign ch_1_en = ch_1_ctrl[0] ;
assign ch_1_target = ch_1_ctrl[4] ;
assign ch_1_size = ch_1_ctrl[17:8] ;

assign ch_2_en = ch_2_ctrl[0] ;
assign ch_2_target = ch_2_ctrl[4] ;
assign ch_2_size = ch_2_ctrl[17:8] ;

assign ch_3_en = ch_3_ctrl[0] ;
assign ch_3_target = ch_3_ctrl[4] ;
assign ch_3_size = ch_3_ctrl[17:8] ;

// ==============================
// AHB 读回寄存器值
// CPU 读地址 → 把对应寄存器放到 HRDATA
// ==============================
always@(posedge HCLK or negedge HRESETn)begin
if(!HRESETn)
HRDATA <= 32’h0;
// 读通道0
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+0 ) HRDATA <= ch_0_ctrl;
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+4 ) HRDATA <= ch_0_sour;
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+8 ) HRDATA <= ch_0_dest;
// 读通道1
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+12) HRDATA <= ch_0_ctrl; // BUG:应是ch_1_ctrl
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+16) HRDATA <= ch_1_sour;
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+20) HRDATA <= ch_1_dest;
// 读通道2
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+24) HRDATA <= ch_2_ctrl;
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+28) HRDATA <= ch_2_sour;
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+32) HRDATA <= ch_2_dest;
// 读通道3
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+36) HRDATA <= ch_3_ctrl;
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+40) HRDATA <= ch_3_sour;
else if(ahb_read==1’b1 && HADDR==BASE_ADDR+44) HRDATA <= ch_3_dest;
end

// ==============================
// AHB 固定输出
// ==============================
assign HRESP = 0; // 无错误
assign HREADYOUT = 1; // 永远就绪(零等待)

endmodule

留言

您的邮箱地址不会被公开。 必填项已用 * 标注