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

老师=CPU,DMA=全能助理,无人机=运输工具,AHB=主干道,AHB控制器=道路管理员,FIFO=办公室中转货架

// 本模块:DMA的AHB主控制器 —— 【道路管理员】
// 作用:按照AHB主干道规则,帮DMA助理收发快递(数据)
`timescale 1ns / 10ps

module dmac_ahb_ctrl(
// 系统时钟与复位 —— 道路节拍、系统重启
input clk, // 时钟:道路每一拍走一步
input rst, // 复位:清空任务,重新开始

// 来自DMA助理的命令 —— 助理让道路管理员干活
input wr, // 写请求:送快递
input rd, // 读请求:取快递
input [31:0]addr, // 地址:快递点/目的地地址
input [31:0]wdata, // 写数据:要送出去的快递

// 送回给DMA助理的结果 —— 告诉助理取到快递了
output [31:0]rdata, // 读到的数据:取回来的快递
output rd_en, // 读有效:快递已到手,可以拿走

// AHB 主干道外部信号 —— 道路规则信号
output hsel, // 选中从设备:找到目标快递点
output [1:0]htrans, // 传输类型:开始一次新运输
output [2:0]hsize, // 数据位宽:一次运多大包裹(32位)
output hwrite, // 读写方向:1=送快递,0=取快递
output [31:0]haddr, // AHB总线上的地址:报位置
output reg [31:0]hwdata, // AHB写数据:放到主干道上的快递
input hreadyin, // 从设备就绪:对方准备好了,可以交接
input hresp, // 响应:运输是否出错
input [31:0]hrdata // 读回数据:从主干道拿到的快递
);

// 道路管理员的3种工作状态
parameter IDLE = 3’b001; // 空闲:没事干,待命
parameter S0 = 3’b010; // 地址阶段:报地址、报任务
parameter S1 = 3’b100; // 数据阶段:真正搬快递

// 内部寄存器:用来暂存地址、数据、延时打拍(保证流水线对齐)
reg [31:0] addr_d; // 暂存目标地址
reg [31:0] data_1d; // 暂存要送的快递
reg wr_d ; // 写请求延时1拍
reg wr_2d; // 写请求延时2拍
reg rd_d ; // 读请求延时1拍
reg rd_2d; // 读请求延时2拍
reg [2:0] c_state; // 当前状态
reg [2:0] n_state; // 下一个状态

// ====================== 状态机第一段:时序更新 ======================
// 每来一个时钟节拍,更新当前状态
always @(posedge clk or negedge rst) begin
          if(!rst)
                  c_state <= IDLE; // 复位→空闲
          else
                  c_state <= n_state; // 否则走到下一步
end

// ====================== 状态机第二段:组合逻辑判断下一步 ======================
// 道路管理员根据当前状态,决定下一步做什么
always @(*) begin
          case (c_state)
                    IDLE : begin // 空闲
                           if(wr||rd) // 助理派任务:送/取快递
                                     n_state = S0; // → 进入地址周期
                           else
                                     n_state = IDLE; // 没任务,继续休息
                           end

                     S0 : begin // 地址周期:报完地址立刻进数据周期
                            n_state = S1;
                     end

                     S1 :begin // 数据周期:等对方就绪
                            if(hreadyin==1’b1 && (wr||rd)) // 对方就绪+还有任务
                                      n_state = S0; // 连续运输
                            else if(hreadyin==1’b1) // 对方就绪+没任务
                                      n_state = IDLE; // 结束,回家
                            else
                                      n_state = S1; // 继续等待
                     end
                     default: n_state = IDLE ;
          endcase
end

// ====================== 请求信号延时打拍(AHB流水线必须) ======================
// 让请求信号延时1~2拍,和地址、数据对齐,不跑飞
always@(posedge clk or negedge rst) begin
          if (!rst) begin
                     wr_d <= 1’b0;
                     wr_2d <= 1’b0;
                     rd_d <= 1’b0;
                     rd_2d<= 1’b0;
           end else begin
                     wr_d <= wr;
                     rd_d <= rd;
                     wr_2d <=wr_d;
                     rd_2d<= rd_d;
            end
end

// ====================== 锁存地址:记住要去哪个快递点 ======================
always@(posedge clk or negedge rst) begin
          if(!rst) begin
                    addr_d<=32’h0;
          end else if(wr || rd) begin // 有任务时,把地址记下来
                    ddr_d<=addr;
          end
end

// ====================== 锁存要送的快递 ======================
always@(posedge clk or negedge rst) begin
           if(!rst) begin
                    data_1d<=32’h0;
           end else if(wr) begin // 送快递时,先把快递存好
                    data_1d<=wdata;
           end
end

// ====================== 产生AHB控制信号 ======================
// 选中设备:找到快递点
assign hsel = (c_state==S0)||(c_state==S1 &&(wr_d || rd_d)) ;

// 传输类型:NONSEQ(开始一次新运输)
assign htrans = ( hsel == 1’b1 )? 2’h2:2’h0;

// 数据位宽:32位(标准快递大小)
assign hsize = ( hsel == 1’b1 )? 3’h2:3’h0;

// 读写方向:送快递=1,取快递=0
assign hwrite =wr_d ;

// 输出地址到主干道
assign haddr = ( hsel == 1’b1 )?addr_d:32’h0;

// ====================== 往主干道放要送的快递 ======================
always@(posedge clk or negedge rst) begin
         if(!rst) begin
                  hwdata<=32’h0;
         end else if(hsel) begin // 选中目标后,把快递放路上
                  hwdata<=data_1d;
         end
end

// ====================== 读有效信号:快递取到了! ======================
// 条件:数据周期 + 对方就绪 + 是取快递任务
assign rd_en = c_state == S1 && hreadyin==1’b1&& (rd_2d);

// 把取到的快递交给DMA助理
assign rdata = (rd_en == 1’b1 ) ? hrdata : 32’h0;

endmodule

 

 

留言

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