<<<StartOfFile:DMAC/RTL/DMAC_ENGINE.sv>>>
module DMAC_ENGINE
(
    input wire clk,
    input wire rst_n, // _n means active low

    // configuration registers
    input wire [31:0] src_addr_i,
    input wire [31:0] dst_addr_i,
    input wire [15:0] byte_len_i,
    input wire start_i,
    output wire done_o,

    // AMBA AXI interface (AW channel)
    output wire [3:0] awid_o,
    output wire [31:0] awaddr_o,
    output wire [3:0] awlen_o,
    output wire [2:0] awsize_o,
    output wire [1:0] awburst_o,
    output wire awvalid_o,
    input wire awready_i,

    // AMBA AXI interface (W channel)
    output wire [3:0] wid_o,
    output wire [31:0] wdata_o,
    output wire [3:0] wstrb_o,
    output wire wlast_o,
    output wire wvalid_o,
    input wire wready_i,

    // AMBA AXI interface (B channel)
    input wire [3:0] bid_i,
    input wire [1:0] bresp_i,
    input wire bvalid_i,
    output wire bready_o,

    // AMBA AXI interface (AR channel)
    output wire [3:0] arid_o,
    output wire [31:0] araddr_o,
    output wire [3:0] arlen_o,
    output wire [2:0] arsize_o,
    output wire [1:0] arburst_o,
    output wire arvalid_o,
    input wire arready_i,

    // AMBA AXI interface (R channel)
    input wire [3:0] rid_i,
    input wire [31:0] rdata_i,
    input wire [1:0] rresp_i,
    input wire rlast_i,
    input wire rvalid_i,
    output wire rready_o
);

    // mnemonics for state values
    localparam S_IDLE = 3'd0,
                                S_RREQ = 3'd1,
                                S_RDATA = 3'd2,
                                S_WREQ = 3'd3,
                                S_WDATA = 3'd4;

    reg [2:0] state, state_n;

    reg [31:0] src_addr, src_addr_n;
    reg [31:0] dst_addr, dst_addr_n;
    reg [15:0] cnt, cnt_n;
    reg [3:0] wcnt, wcnt_n;

    reg arvalid,
                                rready,
                                awvalid,
                                wvalid,
                                wlast,
                                done;

    wire fifo_full,
                                fifo_empty;
    reg fifo_wren,
                                fifo_rden;
    wire [31:0] fifo_rdata;


    // it's desirable to code registers in a simple way
    always_ff @(posedge clk)
        if (!rst_n) begin
            state <= S_IDLE;

            src_addr <= 32'd0;
            dst_addr <= 32'd0;
            cnt <= 16'd0;

            wcnt <= 4'd0;
        end
        else begin
            state <= state_n;

            src_addr <= src_addr_n;
            dst_addr <= dst_addr_n;
            cnt <= cnt_n;

            wcnt <= wcnt_n;
        end


    // this block programs output values and next register values
    // based on states.
    always_comb begin
        // ********************** 
        // ********************** 
        // FILL YOUR CODE HERE
        // ********************** 
        // ********************** 
    end

    DMAC_FIFO u_fifo
    (
        .clk (clk),
        .rst_n (rst_n),

        .full_o (fifo_full),
        .wren_i (fifo_wren),
        .wdata_i (rdata_i),

        .empty_o (fifo_empty),
        .rden_i (fifo_rden),
        .rdata_o (fifo_rdata)
    );

    // Output assigments
    assign done_o = done;

    assign awid_o = 4'd0;
    assign awaddr_o = dst_addr;
    assign awlen_o = (cnt >= 'd64) ? 4'hF: cnt[5:2]-4'h1;
    assign awsize_o = 3'b010; // 4 bytes per transfer
    assign awburst_o = 2'b01; // incremental
    assign awvalid_o = awvalid;

    assign wid_o = 4'd0;
    assign wdata_o = fifo_rdata;
    assign wstrb_o = 4'b1111; // all bytes within 4 byte are valid
    assign wlast_o = wlast;
    assign wvalid_o = wvalid;

    assign bready_o = 1'b1;

    assign arvalid_o = arvalid;
    assign araddr_o = src_addr;
    assign arid_o = 4'd0;
    assign arlen_o = (cnt >= 'd64) ? 4'hF: cnt[5:2]-4'h1;
    assign arsize_o = 3'b010; // 4 bytes per transfer
    assign arburst_o = 2'b01; // incremental
    assign arvalid_o = arvalid;

    assign rready_o = rready & !fifo_full;

endmodule
<<<EndOfFile:DMAC/RTL/DMAC_ENGINE.sv>>>



{ "signal": [
    { "name": "clk", "wave": "p....|....|.......|....." },
    { "name": "state", "wave": "2.3.4|....|..5.6..|..3.4", "data": ["IDLE", "RREQ", "RDATA", "WREQ", "WDATA", "RREQ"] },
    { "name": "write to CMD", "wave": "010..|....|.......|.....", "data": ["1"] },
    {},
    [ "AR ch",
        { "name": "ARVALID(out)", "wave": "0.1.0|....|.......|.....", "data": ["SRC"] },
        { "name": "ARADDR(out)", "wave": "x.3.x|....|.......|.....", "data": ["SRC"] },
        { "name": "ARLEN(out)", "wave": "2....|....|.......|.....", "data": ["15"] },
        { "name": "ARREADY(in)", "wave": "0..10|....|.......|....." },
    ],
    [ "R ch",
        { "name": "RREADY(out)", "wave": "0...1|....|..0....|....." },
        { "name": "RVALID(in)", "wave": "0....|.1..|..0....|....." },
        { "name": "RLAST(in)", "wave": "0....|....|.10....|....." },
        { "name": "RDATA(in)", "wave": "x....|.444|44x....|.....", "data": ["D0", "D1", "D2", "D14", "D15"] },
    ],
    [ "AW ch",
        { "name": "AWVALID(out)", "wave": "0....|....|..1.0..|....." },
        { "name": "AWADDR(out)", "wave": "x....|....|..5.x..|.....", "data": ["DST"] },
        { "name": "AWLEN(out)", "wave": "2....|....|.......|.....", "data": ["15"] },
        { "name": "AWREADY(in)", "wave": "0....|....|...10..|....." },
    ],
    [ "W ch",
        { "name": "WVALID(out)", "wave": "0....|....|....1..|..0.." },
        { "name": "WDATA(out)", "wave": "x....|....|....444|44x..", "data": ["D0", "D1", "D2", "D14", "D15"] },
        { "name": "WLAST(out)", "wave": "0....|....|.......|.10.." },
        { "name": "WREADY(in)", "wave": "0....|....|....1..|..0.." }
    ]
  ],
    "head" : {
    "tick" : "0"
    },
     "foot" : {
     "tick" : "0"
     }
  }
그림 3. DMA operation with burst transfers. At a time, a request reads/writes 16 cycles of data.

+-------+-------------------------------------------------------------------------------------+------------+-----------------------------------------------------------+-----------------------------------------+
| State | Major outputs | Next State | Next state transition condition | Notes |
| +---------+--------+---------------------------------------+-------------------+------+ | | |
| | ARVALID | RREADY | AWVALID | WVALID | done | | | |
+-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+
| IDLE | 0 | 0 | 0 | 0 | 1 | RREQ | (DMA_CMD.start is written as 1) and (DMA_LEN.byte_len!=0) | On moving out, |
| | | | | | | | | - Copy DMA_SRC to SRC_ADDR. |
| | | | | | | | | - Copy DMA_DST to DST_ADDR |
| | | | | | | | | - Copy DMA_LEN to the internal counter |
+-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+
| RREQ | 1 | 0 | 0 | 0 | 0 | RDATA | ARREADY=1 | On moving out, |
| | | | | | | | | - Increment ARADDR by 4 |
| | | | | | | | | |
| | | | | | | | | ARLEN = (cnt>=64) ? 'hF : cnt[5:2]-4'h1 |
+-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+
| RDATA | 0 | 1 | 0 | 0 | 0 | WREQ | (RVALID=1) & (RLAST) | Push data to FIFO |
| | | | | | +------------+-----------------------------------------------------------+-----------------------------------------+
| | | | | | | RDATA | (RVALID) & (!RLAST) | Push data to FIFO |
+-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+
| WREQ | 0 | 0 | 1 | 0 | 0 | WDATA | AWREADY=1 | On moving out, |
| | | | AWLEN=(cnt>=64) ? 'hF : cnt[5:2]-4'h1 | | | | | - Increment AWADDR by 4 |
| | | | | | | | | - Decrement the internal counter by 4 |
+-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+
| WDATA | 0 | 0 | 0 | 1 | 0 | RREQ | (WREADY=1) (!WLAST) & (counter!=0) | Pop data from FIFO |
| | | | | WLAST=(wcnt=='d0) | | | | Decrement wcnt |
| | | | | | +------------+-----------------------------------------------------------+-----------------------------------------+
| | | | | | | IDLE | (WREADY=1) (WLAST) & (counter==0) | Pop data from FIFO |
+-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+



<<StartOfFile:DMAC/RTL/DMAC_CFG.sv>>>
module DMAC_CFG
(
    input wire clk,
    input wire rst_n, // _n means active low

    // AMBA APB interface
    input wire psel_i,
    input wire penable_i,
    input wire [11:0] paddr_i,
    input wire pwrite_i,
    input wire [31:0] pwdata_i,
    output reg pready_o,
    output reg [31:0] prdata_o,
    output reg pslverr_o,

    // configuration registers
    output reg [31:0] src_addr_o,
    output reg [31:0] dst_addr_o,
    output reg [15:0] byte_len_o,
    output wire start_o,
    input wire done_i
);

    // Configuration register to read/write
    reg [31:0] src_addr;
    reg [31:0] dst_addr;
    reg [15:0] byte_len;

    //----------------------------------------------------------
    // Write
    //----------------------------------------------------------
    // an APB write occurs when PSEL & PENABLE & PWRITE
    // clk : __--__--__--__--__--__--__--__--__--__--
    // psel : ___--------_____________________________
    // penable : _______----_____________________________
    // pwrite : ___--------_____________________________
    // wren : _______----_____________________________
    //
    // DMA start command must be asserted when APB writes 1 to the DMA_CMD
    // register
    // clk : __--__--__--__--__--__--__--__--__--__--
    // psel : ___--------_____________________________
    // penable : _______----_____________________________
    // pwrite : ___--------_____________________________
    // paddr : |DMA_CMD|
    // pwdata : | 1 |
    // start : _______----_____________________________

    wire wren = psel_i & penable_i & pwrite_i;

    always @(posedge clk) begin
        if (!rst_n) begin
            src_addr <= 32'd0;
            dst_addr <= 32'd0;
            byte_len <= 16'd0;
        end
        else if (wren) begin
            case (paddr_i)
                'h100: src_addr <= pwdata_i[31:0];
                'h104: dst_addr <= pwdata_i[31:0];
                'h108: byte_len <= pwdata_i[15:0];
            endcase
        end
    end
    wire start = wren & (paddr_i=='h10C) & pwdata_i[0];

    //----------------------------------------------------------
    // READ
    //----------------------------------------------------------
    // an APB read occurs when PSEL & PENABLE & !PWRITE
    // To make read data a direct output from register,
    // this code shall buffer the muxed read data into a register
    // in the SETUP cycle (PSEL & !PENABLE)
    // clk : __--__--__--__--__--__--__--__--__--__--
    // psel : ___--------_____________________________
    // penable : _______----_____________________________
    // pwrite : ________________________________________
    // reg update : ___----_________________________________
    // prdata : |DATA

    reg [31:0] rdata;

    always @(posedge clk) begin
        if (!rst_n) begin
            rdata <= 32'd0;
        end
        else if (psel_i & !penable_i & !pwrite_i) begin // in the setup cycle in the APB state diagram
            case (paddr_i)
                'h0: rdata <= 32'h0001_2024;
                'h100: rdata <= src_addr;
                'h104: rdata <= dst_addr;
                'h108: rdata <= {16'd0, byte_len};
                'h110: rdata <= {31'd0, done_i};
                default: rdata <= 32'd0;
            endcase
        end
    end

    // output assignments
    assign pready_o = 1'b1;
    assign prdata_o = rdata;
    assign pslverr_o = 1'b0;

    assign src_addr_o = src_addr;
    assign dst_addr_o = dst_addr;
    assign byte_len_o = byte_len;
    assign start_o = start;

endmodule
<<<EndOfFile:DMAC/RTL/DMAC_CFG.sv>>>



<<<StartOfFile:DMAC/RTL/DMAC_FIFO.sv>>>
module DMAC_FIFO #(
    parameter DEPTH_LG2 = 4,
    parameter DATA_WIDTH = 32
    )
(
    input wire clk,
    input wire rst_n,

    output wire full_o,
    input wire wren_i,
    input wire [DATA_WIDTH-1:0] wdata_i,

    output wire empty_o,
    input wire rden_i,
    output wire [DATA_WIDTH-1:0] rdata_o
);

    localparam FIFO_DEPTH = (1<<DEPTH_LG2);

    reg [DATA_WIDTH-1:0] data[FIFO_DEPTH];

    reg full, full_n,
                                        empty, empty_n;
    reg [DEPTH_LG2:0] wrptr, wrptr_n,
                                        rdptr, rdptr_n;

    // reset entries to all 0s
    always_ff @(posedge clk)
        if (!rst_n) begin
            full <= 1'b0;
            empty <= 1'b1; // empty after as reset

            wrptr <= {(DEPTH_LG2+1){1'b0}};
            rdptr <= {(DEPTH_LG2+1){1'b0}};

            for (int i=0; i<FIFO_DEPTH; i++) begin
                data[i] <= {DATA_WIDTH{1'b0}};
            end
        end
        else begin
            full <= full_n;
            empty <= empty_n;

            wrptr <= wrptr_n;
            rdptr <= rdptr_n;

            if (wren_i) begin
                data[wrptr[DEPTH_LG2-1:0]] <= wdata_i;
            end
        end

    always_comb begin
        wrptr_n = wrptr;
        rdptr_n = rdptr;

        if (wren_i) begin
            wrptr_n = wrptr + 'd1;
        end

        if (rden_i) begin
            rdptr_n = rdptr + 'd1;
        end

        empty_n = (wrptr_n == rdptr_n);
        full_n = (wrptr_n[DEPTH_LG2]!=rdptr_n[DEPTH_LG2])
                                     &(wrptr_n[DEPTH_LG2-1:0]==rdptr_n[DEPTH_LG2-1:0]);

    end

    // synthesis translate_off
    always @(posedge clk) begin
        if (full_o & wren_i) begin
            \$display("FIFO overflow");
            @(posedge clk);
            \$finish;
        end
    end

    always @(posedge clk) begin
        if (empty_o & rden_i) begin
            \$display("FIFO underflow");
            @(posedge clk);
            \$finish;
        end
    end
    // synthesis translate_on

    assign full_o = full;
    assign empty_o = empty;
    assign rdata_o = data[rdptr[DEPTH_LG2-1:0]];

endmodule
<<<EndOfFile:DMAC/RTL/DMAC_FIFO.sv>>>



<<<StartOfFile:DMAC/RTL/DMAC_TOP.sv>>>
module DMAC_TOP
(
    input wire clk,
    input wire rst_n, // _n means active low

    // AMBA APB interface
    input wire psel_i,
    input wire penable_i,
    input wire [11:0] paddr_i,
    input wire pwrite_i,
    input wire [31:0] pwdata_i,
    output reg pready_o,
    output reg [31:0] prdata_o,
    output reg pslverr_o,

    // AMBA AXI interface (AW channel)
    output wire [3:0] awid_o,
    output wire [31:0] awaddr_o,
    output wire [3:0] awlen_o,
    output wire [2:0] awsize_o,
    output wire [1:0] awburst_o,
    output wire awvalid_o,
    input wire awready_i,

    // AMBA AXI interface (AW channel)
    output wire [3:0] wid_o,
    output wire [31:0] wdata_o,
    output wire [3:0] wstrb_o,
    output wire wlast_o,
    output wire wvalid_o,
    input wire wready_i,

    // AMBA AXI interface (B channel)
    input wire [3:0] bid_i,
    input wire [1:0] bresp_i,
    input wire bvalid_i,
    output wire bready_o,

    // AMBA AXI interface (AR channel)
    output wire [3:0] arid_o,
    output wire [31:0] araddr_o,
    output wire [3:0] arlen_o,
    output wire [2:0] arsize_o,
    output wire [1:0] arburst_o,
    output wire arvalid_o,
    input wire arready_i,

    // AMBA AXI interface (R channel)
    input wire [3:0] rid_i,
    input wire [31:0] rdata_i,
    input wire [1:0] rresp_i,
    input wire rlast_i,
    input wire rvalid_i,
    output wire rready_o
);

    wire [31:0] src_addr;
    wire [31:0] dst_addr;
    wire [15:0] byte_len;
    wire start;
    wire done;

    DMAC_CFG u_cfg(
        .clk (clk),
        .rst_n (rst_n),

        // AMBA APB interface
        .psel_i (psel_i),
        .penable_i (penable_i),
        .paddr_i (paddr_i),
        .pwrite_i (pwrite_i),
        .pwdata_i (pwdata_i),
        .pready_o (pready_o),
        .prdata_o (prdata_o),
        .pslverr_o (pslverr_o),

        .src_addr_o (src_addr),
        .dst_addr_o (dst_addr),
        .byte_len_o (byte_len),
        .start_o (start),
        .done_i (done)
    );

    DMAC_ENGINE u_engine(
        .clk (clk),
        .rst_n (rst_n),

        // configuration registers
        .src_addr_i (src_addr),
        .dst_addr_i (dst_addr),
        .byte_len_i (byte_len),
        .start_i (start),
        .done_o (done),

        // AMBA AXI interface (AW channel)
        .awid_o (awid_o),
        .awaddr_o (awaddr_o),
        .awlen_o (awlen_o),
        .awsize_o (awsize_o),
        .awburst_o (awburst_o),
        .awvalid_o (awvalid_o),
        .awready_i (awready_i),

        // AMBA AXI interface (W channel)
        .wid_o (wid_o),
        .wdata_o (wdata_o),
        .wstrb_o (wstrb_o),
        .wlast_o (wlast_o),
        .wvalid_o (wvalid_o),
        .wready_i (wready_i),

        // AMBA AXI interface (B channel)
        .bid_i (bid_i),
        .bresp_i (bresp_i),
        .bvalid_i (bvalid_i),
        .bready_o (bready_o),

        // AMBA AXI interface (AR channel)
        .arid_o (arid_o),
        .araddr_o (araddr_o),
        .arlen_o (arlen_o),
        .arsize_o (arsize_o),
        .arburst_o (arburst_o),
        .arvalid_o (arvalid_o),
        .arready_i (arready_i),

        // AMBA AXI interface (R channel)
        .rid_i (rid_i),
        .rdata_i (rdata_i),
        .rresp_i (rresp_i),
        .rlast_i (rlast_i),
        .rvalid_i (rvalid_i),
        .rready_o (rready_o)
    );

endmodule
<<<EndOfFile:DMAC/RTL/DMAC_TOP.sv>>>



<<<StartOfFile:DMAC/RTL/filelist.f>>>
-sverilog \$LAB_PATH/RTL/DMAC_TOP.sv
-sverilog \$LAB_PATH/RTL/DMAC_CFG.sv
-sverilog \$LAB_PATH/RTL/DMAC_ENGINE.sv
-sverilog \$LAB_PATH/RTL/DMAC_FIFO.sv
<<<EndOfFile:DMAC/RTL/filelist.f>>>



<<<StartOfFile:DMAC/SIM/TB/AXI_INTF.sv>>>
`include "../TB/AXI_TYPEDEF.svh"

interface AXI_AW_CH
#(
    parameter ADDR_WIDTH = `AXI_ADDR_WIDTH,
    parameter ID_WIDTH = `AXI_ID_WIDTH
 )
(
    input clk
);
    logic awvalid;
    logic awready;
    logic [ID_WIDTH-1:0] awid;
    logic [ADDR_WIDTH-1:0] awaddr;
    logic [3:0] awlen;
    logic [2:0] awsize;
    logic [1:0] awburst;

endinterface

interface AXI_W_CH
#(
    parameter DATA_WIDTH = `AXI_DATA_WIDTH,
    parameter ID_WIDTH = `AXI_ID_WIDTH
 )
(
    input clk
);
    logic wvalid;
    logic wready;
    logic [ID_WIDTH-1:0] wid;
    logic [DATA_WIDTH-1:0] wdata;
    logic [DATA_WIDTH/8-1:0] wstrb;
    logic wlast;

endinterface

interface AXI_B_CH
#(
    parameter ID_WIDTH = `AXI_ID_WIDTH
 )
(
    input clk
);
    logic bvalid;
    logic bready;
    logic [ID_WIDTH-1:0] bid;
    logic [1:0] bresp;

endinterface

interface AXI_AR_CH
#(
    parameter ADDR_WIDTH = `AXI_ADDR_WIDTH,
    parameter ID_WIDTH = `AXI_ID_WIDTH
 )
(
    input clk
);
    logic arvalid;
    logic arready;
    logic [ID_WIDTH-1:0] arid;
    logic [ADDR_WIDTH-1:0] araddr;
    logic [3:0] arlen;
    logic [2:0] arsize;
    logic [1:0] arburst;

endinterface

interface AXI_R_CH
#(
    parameter DATA_WIDTH = `AXI_DATA_WIDTH,
    parameter ID_WIDTH = `AXI_ID_WIDTH
 )
(
    input clk
);
    logic rvalid;
    logic rready;
    logic [ID_WIDTH-1:0] rid;
    logic [DATA_WIDTH-1:0] rdata;
    logic [1:0] rresp;
    logic rlast;

endinterface

interface APB (
    input clk
);
    logic psel;
    logic penable;
    logic [31:0] paddr;
    logic pwrite;
    logic [31:0] pwdata;
    logic pready;
    logic [31:0] prdata;
    logic pslverr;

    modport master (
        input clk,
        input pready, prdata, pslverr,
        output psel, penable, paddr, pwrite, pwdata
    );

    task init();
        psel = 1'b0;
        penable = 1'b0;
        paddr = 32'd0;
        pwrite = 1'b0;
        pwdata = 32'd0;
    endtask

    task write(input int addr,
               input int data);
        #1
        psel = 1'b1;
        penable = 1'b0;
        paddr = addr;
        pwrite = 1'b1;
        pwdata = data;
        @(posedge clk);
        #1
        penable = 1'b1;
        @(posedge clk);

        while (pready==1'b0) begin
            @(posedge clk);
        end

        psel = 1'b0;
        penable = 1'b0;
        paddr = 'hX;
        pwrite = 1'bx;
        pwdata = 'hX;
    endtask

    task read(input int addr,
              output int data);
        #1
        psel = 1'b1;
        penable = 1'b0;
        paddr = addr;
        pwrite = 1'b0;
        pwdata = 'hX;
        @(posedge clk);
        #1
        penable = 1'b1;
        @(posedge clk);

        while (pready==1'b0) begin
            @(posedge clk);
        end
        data = prdata;

        psel = 1'b0;
        penable = 1'b0;
        paddr = 'hX;
        pwrite = 1'bx;
        pwdata = 'hX;
    endtask

endinterface
<<<EndOfFile:DMAC/SIM/TB/AXI_INTF.sv>>>



<<<StartOfFile:DMAC/SIM/TB/AXI_SLAVE.sv>>>
`include "../TB/AXI_TYPEDEF.svh"

module AXI_SLAVE
#(
    parameter ADDR_WIDTH = 16,
    parameter DATA_WIDTH = `AXI_DATA_WIDTH,
    parameter ID_WIDTH = `AXI_ID_WIDTH,
    parameter AWREADY_DELAY = 1,
    parameter ARREADY_DELAY = 1,
    parameter AR2R_DELAY = 50
)
(
    input wire clk,
    input wire rst_n, // _n means active low

    AXI_AW_CH aw_ch,
    AXI_W_CH w_ch,
    AXI_B_CH b_ch,
    AXI_AR_CH ar_ch,
    AXI_R_CH r_ch
);

    localparam DATA_DEPTH = 1<<ADDR_WIDTH;

    logic [7:0] mem[DATA_DEPTH];

    function void write_byte(int addr, input bit [7:0] wdata);
        mem[addr] = wdata;
    endfunction

    function void write_word(int addr, input bit [31:0] wdata);
        for (int i=0; i<4; i++) begin
            write_byte(addr+i, wdata[8*i +: 8]); // [i*8+7:i*8]
        end
    endfunction

    function bit [7:0] read_byte(int addr);
        read_byte = mem[addr];
    endfunction

    function bit [31:0] read_word(int addr);
        for (int i=0; i<4; i++) begin
            read_word[8*i +: 8] = read_byte(addr+i);// [i*8+7:i*8]
        end
    endfunction

    //----------------------------------------------------------
    // write channels (AW, W, B)
    //----------------------------------------------------------
    localparam logic [1:0] S_W_IDLE = 0,
                                S_W_AWREADY = 1,
                                S_W_BURST = 2,
                                S_W_RESP = 3;

    logic [1:0] wstate, wstate_n;
    logic [7:0] wcnt, wcnt_n;

    logic [ADDR_WIDTH-1:0] waddr, waddr_n;
    logic [ID_WIDTH-1:0] wid, wid_n;
    logic [3:0] wlen, wlen_n;

    always_ff @(posedge clk)
        if (!rst_n) begin
            wstate <= S_W_IDLE;

            wcnt <= 8'd0;
            waddr <= {ADDR_WIDTH{1'b0}};
            wid <= {ID_WIDTH{1'b0}};
            wlen <= 4'd0;
        end
        else begin
            wstate <= wstate_n;

            wcnt <= wcnt_n;
            waddr <= waddr_n;
            wid <= wid_n;
            wlen <= wlen_n;
        end

    always @(*) begin
        wstate_n = wstate;

        wcnt_n = wcnt;
        waddr_n = waddr;
        wid_n = wid;
        wlen_n = wlen;

        aw_ch.awready = 1'b0;
        w_ch.wready = 1'b0;
        b_ch.bvalid = 1'b0;

        case (wstate)
            S_W_IDLE: begin
                if (aw_ch.awvalid) begin
                    if (AWREADY_DELAY == 0) begin
                        waddr_n = aw_ch.awaddr;
                        wid_n = aw_ch.awid;
                        wlen_n = aw_ch.awlen;
                        aw_ch.awready = 1'b1;
                        wstate_n = S_W_BURST;
                    end
                    else begin
                        wcnt_n = AWREADY_DELAY-1;
                        wstate_n = S_W_AWREADY;
                    end
                end
            end
            S_W_AWREADY: begin
                if (wcnt==0) begin
                    waddr_n = aw_ch.awaddr;
                    wid_n = aw_ch.awid;
                    wlen_n = aw_ch.awlen;
                    aw_ch.awready = 1'b1;
                    wstate_n = S_W_BURST;
                end
                else begin
                    wcnt_n = wcnt - 8'd1;
                end
            end
            S_W_BURST: begin
                w_ch.wready = 1'b1;
                if (w_ch.wvalid) begin
                    for (int i=0; i<DATA_WIDTH/8; i++) begin
                        write_byte(waddr + i, w_ch.wdata[i*8 +: 8]); // [i*8+7:i*8]
                    end
                    waddr_n = waddr + (DATA_WIDTH/8);
                    if (wlen==4'd0) begin
                        wstate_n = S_W_RESP;
                    end
                    else begin
                        wlen_n = wlen - 4'd1;
                    end
                end
            end
            S_W_RESP: begin
                b_ch.bvalid = 1'b1;
                if (b_ch.bready) begin
                    wstate_n = S_W_IDLE;
                end
            end
        endcase
    end

    //----------------------------------------------------------
    // read channel (AR, R)
    //----------------------------------------------------------
    localparam logic [1:0] S_R_IDLE = 0,
                                S_R_ARREADY = 1,
                                S_R_DELAY = 2,
                                S_R_BURST = 3;

    logic [1:0] rstate, rstate_n;
    logic [7:0] rcnt, rcnt_n;

    logic [ADDR_WIDTH-1:0] raddr, raddr_n;
    logic [ID_WIDTH-1:0] rid, rid_n;
    logic [3:0] rlen, rlen_n;

    always_ff @(posedge clk)
        if (!rst_n) begin
            rstate <= S_R_IDLE;

            rcnt <= 8'd0;
            raddr <= {ADDR_WIDTH{1'b0}};
            rid <= {ID_WIDTH{1'b0}};
            rlen <= 4'd0;
        end
        else begin
            rstate <= rstate_n;

            rcnt <= rcnt_n;
            raddr <= raddr_n;
            rid <= rid_n;
            rlen <= rlen_n;
        end

    always_comb begin
        rstate_n = rstate;

        rcnt_n = rcnt;
        raddr_n = raddr;
        rid_n = rid;
        rlen_n = rlen;

        ar_ch.arready = 1'b0;
        r_ch.rvalid = 1'b0;
        r_ch.rlast = 1'b0;

        case (rstate)
            S_R_IDLE: begin
                if (ar_ch.arvalid) begin
                    if (ARREADY_DELAY == 0) begin
                        raddr_n = ar_ch.araddr;
                        rid_n = ar_ch.arid;
                        rlen_n = ar_ch.arlen;
                        ar_ch.arready = 1'b1;

                        rcnt_n = AR2R_DELAY - 1;
                        rstate_n = S_R_DELAY;
                    end
                    else begin
                        rcnt_n = ARREADY_DELAY-1;
                        rstate_n = S_R_ARREADY;
                    end
                end
            end
            S_R_ARREADY: begin
                if (rcnt==0) begin
                    raddr_n = ar_ch.araddr;
                    rid_n = ar_ch.arid;
                    rlen_n = ar_ch.arlen;
                    ar_ch.arready = 1'b1;

                    rcnt_n = AR2R_DELAY - 1;
                    rstate_n = S_R_DELAY;
                end
                else begin
                    rcnt_n = rcnt - 8'd1;
                end
            end
            S_R_DELAY: begin
                if (rcnt==0) begin
                    rstate_n = S_R_BURST;
                end
                else begin
                    rcnt_n = rcnt - 8'd1;
                end
            end
            S_R_BURST: begin
                r_ch.rvalid = 1'b1;
                r_ch.rlast = (rlen==4'd0);
                for (int i=0; i<DATA_WIDTH/8; i++) begin
                    r_ch.rdata[i*8 +: 8] = read_byte(raddr + i); // [i*8+7:i*8]
                end
                if (r_ch.rready) begin
                    raddr_n = raddr + (DATA_WIDTH/8);
                    if (rlen==4'd0) begin
                        rstate_n = S_R_IDLE;
                    end
                    else begin
                        rlen_n = rlen - 4'd1;
                    end
                end
            end
        endcase
    end

    // output assignments
    assign b_ch.bid = wid;
    assign b_ch.bresp = 2'd0;
    assign r_ch.rid = rid;
    assign r_ch.rresp = 2'd0;

endmodule
<<<EndOfFile:DMAC/SIM/TB/AXI_SLAVE.sv>>>



<<<StartOfFile:DMAC/SIM/TB/AXI_TYPEDEF.svh>>>
`ifndef __AXI_TYPEDEF_SVH__
`define __AXI_TYPEDEF_SVH__

`define AXI_ADDR_WIDTH 32
`define AXI_DATA_WIDTH 32
`define AXI_ID_WIDTH 4

`endif /* __AXI_TYPEDEF_SVH__ */
<<<EndOfFile:DMAC/SIM/TB/AXI_TYPEDEF.svh>>>



<<<StartOfFile:DMAC/SIM/TB/DMAC_TOP_TB.sv>>>
`define IP_VER 32'h000
`define SRC_ADDR 32'h100
`define DST_ADDR 32'h104
`define LEN_ADDR 32'h108
`define STAT_ADDR 32'h110
`define START_ADDR 32'h10c

`define TIMEOUT_CYCLE 999999
module DMAC_TOP_TB ();

    reg clk;
    reg rst_n;

    // clock generation
    initial begin
        clk = 1'b0;

        forever #10 clk = !clk;
    end

    // reset generation
    initial begin
        rst_n = 1'b0; // active at time 0

        repeat (3) @(posedge clk); // after 3 cycles,
        rst_n = 1'b1; // release the reset
    end

    // enable waveform dump
    initial begin
        \$dumpvars(0, u_DUT);
        \$dumpfile("dump.vcd");
    end
 // timeout
 initial begin
  #`TIMEOUT_CYCLE \$display("Timeout!");
  \$finish;
 end

    APB apb_if (.clk(clk));

    AXI_AW_CH aw_ch (.clk(clk));
    AXI_W_CH w_ch (.clk(clk));
    AXI_B_CH b_ch (.clk(clk));
    AXI_AR_CH ar_ch (.clk(clk));
    AXI_R_CH r_ch (.clk(clk));

    task test_init();
        int data;
        apb_if.init();

        @(posedge rst_n); // wait for a release of the reset
        repeat (10) @(posedge clk); // wait another 10 cycles

        apb_if.read(`IP_VER, data);
        \$display("---------------------------------------------------");
        \$display("IP version: %x", data);
        \$display("---------------------------------------------------");

        \$display("---------------------------------------------------");
        \$display("Reset value test");
        \$display("---------------------------------------------------");
        apb_if.read(`SRC_ADDR, data);
        if (data===0)
            \$display("DMA_SRC(pass): %x", data);
        else begin
            \$display("DMA_SRC(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        apb_if.read(`DST_ADDR, data);
        if (data===0)
            \$display("DMA_DST(pass): %x", data);
        else begin
            \$display("DMA_DST(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        apb_if.read(`LEN_ADDR, data);
        if (data===0)
            \$display("DMA_LEN(pass): %x", data);
        else begin
            \$display("DMA_LEN(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        apb_if.read(`STAT_ADDR, data);
        if (data===1)
            \$display("DMA_STATUS(pass): %x", data);
        else begin
            \$display("DMA_STATUS(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
    endtask

    task test_dma(input int src, input int dst, input int len);
        int data;
        int word;
        realtime elapsed_time;

        \$display("---------------------------------------------------");
        \$display("Load data to memory");
        \$display("---------------------------------------------------");
        for (int i=src; i<(src+len); i=i+4) begin
            word = \$random; 
            u_mem.write_word(i, word);
        end

        \$display("---------------------------------------------------");
        \$display("Configuration test");
        \$display("---------------------------------------------------");
        apb_if.write(`SRC_ADDR, src);
        apb_if.read(`SRC_ADDR, data);
        if (data===src)
            \$display("DMA_SRC(pass): %x", data);
        else begin
            \$display("DMA_SRC(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        apb_if.write(`DST_ADDR, dst);
        apb_if.read(`DST_ADDR, data);
        if (data===dst)
            \$display("DMA_DST(pass): %x", data);
        else begin
            \$display("DMA_DST(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        apb_if.write(`LEN_ADDR, len);
        apb_if.read(`LEN_ADDR, data);
        if (data===len)
            \$display("DMA_LEN(pass): %x", data);
        else begin
            \$display("DMA_LEN(fail): %x", data);
            @(posedge clk);
            \$finish;
        end

        \$display("---------------------------------------------------");
        \$display("DMA start");
        \$display("---------------------------------------------------");
        apb_if.write(`START_ADDR, 32'h1);
        elapsed_time = \$realtime;

        \$display("---------------------------------------------------");
        \$display("Wait for a DMA completion");
        \$display("---------------------------------------------------");
        data = 0;
        while (data!=1) begin
            apb_if.read(`STAT_ADDR, data);
            repeat (100) @(posedge clk);
        end
        @(posedge clk);
        elapsed_time = \$realtime - elapsed_time;
        \$timeformat(-9, 0, " ns", 10);
        \$display("Elapsed time for DMA: %t", elapsed_time);

        \$display("---------------------------------------------------");
        \$display("DMA completed");
        \$display("---------------------------------------------------");

        repeat (len) @(posedge clk); // to make sure data is written

        \$display("---------------------------------------------------");
        \$display("verify data");
        \$display("---------------------------------------------------");
        for (int i=0; i<len; i=i+4) begin
            logic [31:0] src_word;
            logic [31:0] dst_word;
            src_word = u_mem.read_word(src+i);
            dst_word = u_mem.read_word(dst+i);
            if (src_word!==dst_word) begin
                \$display("Mismatch! (src:%x @%x, dst:%x @%x", src_word, src+i, dst_word, dst+i);
            end
        end
    endtask

    int src,
                    dst,
                    len;

    // main
    initial begin
        test_init();

        src = 'h0000_1000;
        dst = 'h0000_2000;
        len = 'h0100;
        \$display("===================================================");
        \$display("= 1st trial"); 
        \$display("= Copying %x bytes from %x to %x", len, src, dst);
        \$display("===================================================");
        test_dma(src, dst, len);

        src = 'h1234_1234;
        dst = 'hABCD_ABCC;
        len = 'h0F00;
        \$display("===================================================");
        \$display("= 2nd trial (long transfer)");
        \$display("= Copying %x bytes from %x to %x", len, src, dst);
        \$display("===================================================");
        test_dma(src, dst, len);

        src = 'h4278_0000;
        dst = 'h4278_1000;
        len = 'h0F10;
        \$display("===================================================");
        \$display("= 3rd trial (long transfer-2)");
        \$display("= Copying %x bytes from %x to %x", len, src, dst);
        \$display("===================================================");
        test_dma(src, dst, len);
        \$finish;
    end


    AXI_SLAVE u_mem (
        .clk (clk),
        .rst_n (rst_n),

        .aw_ch (aw_ch),
        .w_ch (w_ch),
        .b_ch (b_ch),
        .ar_ch (ar_ch),
        .r_ch (r_ch)
    );

    DMAC_TOP u_DUT (
        .clk (clk),
        .rst_n (rst_n),

        // APB interface
        .psel_i (apb_if.psel),
        .penable_i (apb_if.penable),
        .paddr_i (apb_if.paddr[11:0]),
        .pwrite_i (apb_if.pwrite),
        .pwdata_i (apb_if.pwdata),
        .pready_o (apb_if.pready),
        .prdata_o (apb_if.prdata),
        .pslverr_o (apb_if.pslverr),

        // AXI AW channel
        .awid_o (aw_ch.awid),
        .awaddr_o (aw_ch.awaddr),
        .awlen_o (aw_ch.awlen),
        .awsize_o (aw_ch.awsize),
        .awburst_o (aw_ch.awburst),
        .awvalid_o (aw_ch.awvalid),
        .awready_i (aw_ch.awready),

        // AXI W channel
        .wid_o (w_ch.wid),
        .wdata_o (w_ch.wdata),
        .wstrb_o (w_ch.wstrb),
        .wlast_o (w_ch.wlast),
        .wvalid_o (w_ch.wvalid),
        .wready_i (w_ch.wready),

        // AXI B channel
        .bid_i (b_ch.bid),
        .bresp_i (b_ch.bresp),
        .bvalid_i (b_ch.bvalid),
        .bready_o (b_ch.bready),

        // AXI AR channel
        .arid_o (ar_ch.arid),
        .araddr_o (ar_ch.araddr),
        .arlen_o (ar_ch.arlen),
        .arsize_o (ar_ch.arsize),
        .arburst_o (ar_ch.arburst),
        .arvalid_o (ar_ch.arvalid),
        .arready_i (ar_ch.arready),

        // AXI R channel
        .rid_i (r_ch.rid),
        .rdata_i (r_ch.rdata),
        .rresp_i (r_ch.rresp),
        .rlast_i (r_ch.rlast),
        .rvalid_i (r_ch.rvalid),
        .rready_o (r_ch.rready)
    );

endmodule
<<<EndOfFile:DMAC/SIM/TB/DMAC_TOP_TB.sv>>>



<<<StartOfFile:DMAC/SIM/TB/filelist.f>>>
\$LAB_PATH/SIM/TB/timescale.v
\$LAB_PATH/SIM/TB/AXI_INTF.sv
\$LAB_PATH/SIM/TB/AXI_SLAVE.sv
\$LAB_PATH/SIM/TB/DMAC_TOP_TB.sv
<<<EndOfFile:DMAC/SIM/TB/filelist.f>>>



<<<StartOfFile:DMAC/SIM/TB/timescale.v>>>
`timescale 1ns/1ps
<<<EndOfFile:DMAC/SIM/TB/timescale.v>>>



<<<StartOfFile:DMAC/SIM/run.compile>>>
#!/bin/bash

source ../../scripts/common.sh

export LAB_PATH="\$PWD/../"
FILELIST_TB="../TB/filelist.f"
FILELIST_RTL="../../RTL/filelist.f"

echo "Cleaning up the old directory"
rm -rf \$RUN_DIR
echo "Creating a new directory"
mkdir -p \$RUN_DIR
cd \$RUN_DIR
echo "Compiling"
\$COMPILE_CMD \$COMPILE_OPTIONS -f \$FILELIST_TB -f \$FILELIST_RTL
<<<EndOfFile:DMAC/SIM/run.compile>>>



<<<StartOfFile:DMAC/SIM/run.compile4cov>>>
#!/bin/bash

source ../../scripts/common.sh

export LAB_PATH="\$PWD/../"
COV_DIR="\$PWD/VDB"
COV_OPTIONS="-cm line+cond+fsm+tgl+branch -cm_dir \$COV_DIR"
FILELIST_TB="../TB/filelist.f"
FILELIST_RTL="../../RTL/filelist.f"

echo "Cleaning up the old directory"
rm -rf \$RUN_DIR
echo "Creating a new directory"
mkdir -p \$RUN_DIR
cd \$RUN_DIR
echo "Compiling"
\$COMPILE_CMD \$COMPILE_OPTIONS \$COV_OPTIONS -f \$FILELIST_TB -f \$FILELIST_RTL
<<<EndOfFile:DMAC/SIM/run.compile4cov>>>



<<<StartOfFile:DMAC/SIM/run.sim>>>
#!/bin/bash

source ../../scripts/common.sh

if [ -e \$RUN_DIR/simv ];
then
 cd \$RUN_DIR
 ./simv
else
 echo "Compile file does not exist"
 exit 1
fi
<<<EndOfFile:DMAC/SIM/run.sim>>>



<<<StartOfFile:DMAC/SIM/run.sim4cov>>>
#!/bin/bash

source ../../scripts/common.sh

COV_DIR="\$PWD/VDB"
COV_OPTIONS="-cm line+cond+fsm+tgl+branch -cm_dir \$COV_DIR"

if [ -e \$RUN_DIR/simv ];
then
 cd \$RUN_DIR
 ./simv \$COV_OPTIONS
else
 echo "Compile file does not exist"
 exit 1
fi
<<<EndOfFile:DMAC/SIM/run.sim4cov>>>



<<<StartOfFile:DMAC/SIM/run.verdi>>>
#!/bin/bash

source ../../scripts/common.sh

export LAB_PATH="\$PWD/../"
FILELIST_TB="../TB/filelist.f"
FILELIST_RTL="../../RTL/filelist.f"

cd \$RUN_DIR
\$VERDI_CMD \$VERDI_OPTIONS -f \$FILELIST_TB -f \$FILELIST_RTL
<<<EndOfFile:DMAC/SIM/run.verdi>>>



<<<StartOfFile:DMAC/SIM/run.verdi4cov>>>
verdi -cov -covdir VDB.vdb/
<<<EndOfFile:DMAC/SIM/run.verdi4cov>>>



<<<StartOfFile:DMAC/SIM/run.waveform>>>
#!/bin/bash

source ../../scripts/common.sh

if [ -e \$RUN_DIR/dump.vcd ];
then
 cd \$RUN_DIR
 \$WAVE_CMD \$WAVE_OPTIONS -i dump.vcd
else
 echo "Dump file does not exist"
 exit 1
fi
<<<EndOfFile:DMAC/SIM/run.waveform>>>


///

Direct Memory Access (DMA) Controller
Design Document V1.0

1 Overview
This document specifies the design and implementation of a Direct Memory Access Controller (DMAC) as a part of System-on-a-Chip (SoC). The main purpose of this DMAC design is to integrate into SoC for exchange a large volume of data between memory and peripherals at high speed. The proposed DMAC works on ARM’s Advanced Microcontroller Bus Architecture (AMBA) specification. The DMAC provides an AMBA APB interface to configure the IP, and an AMBA AXI interface to transfer data.

2 Architecture Specification
2.1 General Description
Some applications require transferring a volume of data between memory and peripherals without any modification on data. In software, it is commonly served by executing the memcpy library function in C, C++ or other languages. In C, the function has the following interface and copies len bytes from the object pointed by src to the object pointed by dst: void* memcpy(void* dst, const void* src, size_t len).
While a pure software-based implementation of memcpy transfers data using CPU instructions, DMA does not use expensive CPU cycles but uses a hardware engine (DMAC) for the transfer. This can significantly speed up data transfers and allows using CPU for other jobs.
2.2 Usage Constraints
Below describe constraints in utilizing DMAC v1.
-The src and dst addresses are physical addresses.
-The src and dst addresses must be a multiple of 4.
-The len must be a multiple of 4.
-The maximum len is 0xFFFF
-Source and destination ranges must not overlap.
2.3 Programming Model
Software can use the following sequence to transfer data using DMAC.
-1.Write the source address to DMA_SRC register
-2.Write the destination address to DMA_DST register
-3.Write length to DMA_LEN register
-4.Write 1 to bit[0] of DMA_CMD register
-5.Wait until DMA_STATUS register has bit[0] as 1.

2.4 Register Map
In order to control DMAC, software can configure the following registers.
+--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+
| Offset | Reg Name | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+
| 0x00 | DMA_VER | version |
+--------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| 0x04~0xFC | Reserved |
+--------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| 0x100 | DMA_SRC | start_addr |
+--------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| 0x104 | DMA_DST | start_addr |
+--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+-------------------------------------------------------------------------+
| 0x108 | DMA_LEN | | | | | | | | | | | | | | | | | byte_len |
+--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+
| 0x10C | DMA_CMD | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | start |
+--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+
| 0x110 | DMA_STATUS | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | done |
+--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+

2.4.1 DMA VERSION
| Field name | Bit range | R/W | Reset value | Desciption |
|------------|-----------|-----|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| version | [31:0] | R | 0x0001_2024 | The version of this DMA controller. The upper 16 bits represent the major version. The lower 16 bits represent the released year of the version. This document describes behaviors of major version 1. |

2.4.2 DMA_SRC
| Field name | Bit range | R/W | Reset value | Desciption |
|------------|-----------|-----|-------------|------------------------------------|
| start_addr | [31:0] | R/W | 0x0000_0000 | start address of the source range. |

2.4.3 DMA_DST
| Field name | Bit range | R/W | Reset value | Desciption |
|------------|-----------|-----|-------------|-----------------------------------------|
| start_addr | [31:0] | R/W | 0x0000_0000 | start address of the destination range. |

2.4.4 DMA_LEN
| Field name | Bit range | R/W | Reset value | Desciption |
|------------|-----------|-----|-------------|-----------------------------------------------------------------------|
| byte_len | [15:0] | R/W | 0x0000 | Number of bytes to be transferred from the source to the destination. |

2.4.5 DMA_CMD Field
| Field name | Bit range | R/W | Reset value | Desciption |
|------------|-----------|-----|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| start | [0] | W | N/A | Writing 1 to this field will initiate a DMA transfer based on DMA_SRC, DMA_DST, and DMA_LEN registers. Software must not write 1 when there’s an on-going transfer. Writing 0 to this field does not affect operation |

2.4.6 DMA_STATUS
| Field name | Bit range | R/W | Reset value | Desciption |
|------------|-----------|-----|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| done | [0] | R | 1 | This field is 1 when there’s no on-going DMA transfer. Software must wait this field to be 1 for a completion of a transfer. Software must not initiate a DMA transfer when this field is 0. |

3 Micro-architecture v1.1 Specification
This section describes microarchitecture of a simple DMAC. It reads data from memory, buffers the data, and write the data into memory. It repeats this procedure until it completes transferring the specified number of bytes.
For simplicity, it read/writes one-cycle data (4 bytes) at a time (in other words, burst-1 transfers). For simplicity, this microarchitecture does not consider write responses from the AXI interface. Later versions will support burst transfers and write responses.

3.1 External Interface
DMAC v1.1 has the following external interfaces to communicate with other hardware IPs.
-AMBA APB interface for configuration
-AMBA AXI interface for data transfer

The image you’ve uploaded is a diagram showing the on-chip interconnect of a computer system. Here’s a detailed description:
The diagram illustrates how the CPU core, memory, and DMAC (Direct Memory Access Controller) are connected through an on-chip interconnect.
The connections also include specific interfaces like Config interface (APB) and Data interface (AXI).
“CPU core” is a box on the left side connected to the central “On-chip interconnect” cloud shape with a bidirectional arrow.
Below the “CPU core,” there’s another box labeled “Memory,” also connected to the “On-chip interconnect” with a bidirectional arrow.
On the right side, there’s a box labeled “DMAC” connected to both “Config interface (APB)” and “Data interface (AXI)” which are in turn connected to the central “On-chip interconnect” with bidirectional arrows.
The arrows indicate that data can flow in both directions between these components.

3.2 Block Diagram
DMAC v1.1 has the following blocks inside.

The diagram is divided into three main blocks labeled “DMAC_TOP,” “DMAC_CFG,” and “DMAC_ENGINE.”
“clk” and “rst” are inputs to the “DMAC_TOP” block.
An arrow labeled “APB” connects the “DMAC_TOP” block to the “DMAC_CFG” block.
Another arrow labeled “AXI” connects both the “DMAC_TOP” and “DMAC_CFG” blocks to the “DMAC_ENGINE” block.
Inside the “DMAC_ENGINE” block, there are four internal components labeled as follows:
SRC_ADDR
DST_ADDR
CNT
DATA BUF
There’s also a small circular graph with nodes labeled 0 to 3 inside this block.
This diagram is likely used to illustrate the flow of data or control signals between these components in a Direct Memory Access Controller configuration. Please let me know if you need more information!

3.3 Configuration Register (lab2)
This block receives read/write requests from the APB and configures the registers describes in Section 2.4.

3.4 Finite State Machine (lab3)
DMA engine utilizes the following state machine to control operations.

The diagram contains five blue circles representing different states: IDLE, RREQ, RDATA, WREQ, and WDATA.
Arrows connect these circles indicating the flow from one state to another.
Each arrow has text annotations that describe the conditions for transitioning from one state to another. For example, transitioning from IDLE to RREQ requires writing 1 to DMA_CMD & LEN!=0, and copying DMA_SRC/DST/LEN.
There are also annotations on the state circles themselves, such as “done=1” on IDLE and “AWVALID=1” on WDATA.

+-------+--------------------------------------------+------------+-----------------------------------------------------------+----------------------------------------+
| State | Major outputs | Next State | Next state transition condition | Notes |
| +---------+--------+---------+--------+------+ | | |
| | ARVALID | RREADY | AWVALID | WVALID | done | | | |
+-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+
| IDLE | 0 | 0 | 0 | 0 | 1 | RREQ | (DMA_CMD.start is written as 1) and (DMA_LEN.byte_len!=0) | On moving out, |
| | | | | | | | | - Copy DMA_SRC to SRC_ADDR. |
| | | | | | | | | - Copy DMA_DST to DST_ADDR |
| | | | | | | | | - Copy DMA_LEN to the internal counter |
+-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+
| RREQ | 1 | 0 | 0 | 0 | 0 | RDATA | ARREADY=1 | On moving out, |
| | | | | | | | | - Increment ARADDR by 4 |
+-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+
| RDATA | 0 | 1 | 0 | 0 | 0 | WREQ | RVALID=1 | On moving out, |
| | | | | | | | | - Buffer RDATA into the data buffer |
+-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+
| WREQ | 0 | 0 | 1 | 0 | 0 | WDATA | AWREADY=1 | On moving out, |
| | | | | | | | | - Increment AWADDR by 4 |
| | | | | | | | | - Decrement the internal counter by 4 |
+-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+
| WDATA | 0 | 0 | 0 | 1 | 0 | RREQ | (WREADY=1) & (counter!=0) | |
| | | | | | +------------+-----------------------------------------------------------+----------------------------------------+
| | | | | | | IDLE | (WREADY=1) & (counter==0) | |
+-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+



{ "signal": [
    { "name": "clk", "wave": "p....|.........." },
    { "name": "state", "wave": "2.3.4|..5.6.2...", "data": ["IDLE", "RREQ", "RDATA", "WREQ", "WDATA", "IDLE"] },
    { "name": "write to CMD", "wave": "010..|..........", "data": ["1"] },
    {},
    [ "AR ch",
        { "name": "ARVALID(out)", "wave": "0.1.0|..........", "data": ["SRC"] },
        { "name": "ARADDR(out)", "wave": "x.3.x|..........", "data": ["SRC"] },
        { "name": "ARLEN(out)", "wave": "2....|..........", "data": ["0"] },
        { "name": "ARREADY(in)", "wave": "0..10|.........." },
    ],
    [ "R ch",
        { "name": "RREADY(out)", "wave": "0...1|..0......." },
        { "name": "RVALID(in)", "wave": "0....|.10......." },
        { "name": "RDATA(in)", "wave": "x....|.4x.......", "data": ["DATA"] },
    ],
    [ "AW ch",
        { "name": "AWVALID(out)", "wave": "0....|..1.0....." },
        { "name": "AWADDR(out)", "wave": "x....|..5.x.....", "data": ["DST"] },
        { "name": "AWLEN(out)", "wave": "2....|..........", "data": ["0"] },
        { "name": "AWREADY(in)", "wave": "0....|...10....." },
    ],
    [ "W ch",
        { "name": "WVALID(out)", "wave": "0....|....1.0..." },
        { "name": "WDATA(out)", "wave": "x....|....4.x...", "data": ["DATA"] },
        { "name": "WREADY(in)", "wave": "0....|.....10..." }
    ]
  ],
    "head" : {
    "tick" : "0"
    },
     "foot" : {
     "tick" : "0"
     }
  }
그림 1. DMA operation with microarchitecture v1.1


4 Micro-architecture v1.2 Specification (lab4)
A problem with microarchitecture v1.1 is that it reads/writes data one-by-one. As memory read takes some time, DMAC v1.1 will suffer from poor performance with a long memory read latency (그림 2). We will improve the microarchitecture to transfer a burst of data to minimize performance degradation.


{ "signal": [
    { "name": "clk", "wave": "p....|.................." },
    { "name": "state", "wave": "2.3.4|..5.6.3.4|..5.6.3.", "data": ["IDLE", "RREQ", "RDATA", "WREQ", "WDATA", "RREQ", "RDATA", "WREQ", "WDATA", "RREQ"] },
    { "name": "write to CMD", "wave": "010..|.........|........", "data": ["1"] },
    {},
    [ "AR ch",
        { "name": "ARVALID(out)", "wave": "0.1.0|......1.0|......1.", "data": ["SRC"] },
        { "name": "ARADDR(out)", "wave": "x.3.x|......3.x|......3.", "data": ["SRC", "SRC+4", "SRC+8"] },
        { "name": "ARLEN(out)", "wave": "2....|.........|........", "data": ["0"] },
        { "name": "ARREADY(in)", "wave": "0..10|.......10|.......1" },
    ],
    [ "R ch",
        { "name": "RREADY(out)", "wave": "0...1|..0.....1|..0....." },
        { "name": "RVALID(in)", "wave": "0....|.10......|.10....." },
        { "name": "RDATA(in)", "wave": "x....|.4x......|.4x.....", "data": ["DATA", "DATA"] },
    ],
    [ "AW ch",
        { "name": "AWVALID(out)", "wave": "0....|..1.0....|..1.0..." },
        { "name": "AWADDR(out)", "wave": "x....|..5.x....|..5.x...", "data": ["DST", "DST+4"] },
        { "name": "AWLEN(out)", "wave": "2....|.........|........", "data": ["0"] },
        { "name": "AWREADY(in)", "wave": "0....|...10....|...10..." },
    ],
    [ "W ch",
        { "name": "WVALID(out)", "wave": "0....|....1.0..|....1.0." },
        { "name": "WDATA(out)", "wave": "x....|....4.x..|....4.x.", "data": ["DATA", "DATA"] },
        { "name": "WREADY(in)", "wave": "0....|.....10..|.....10." }
    ]
  ],
    "head" : {
    "tick" : "0"
    },
     "foot" : {
     "tick" : "0"
     }
  }
그림 2. DMA operation with microarchitecture 1.1. At a time, it transfers single burst of data
In Microarchitecture version 2, DMAC transfers up to 16 cycles of data with a single access.
This can significantly reduce execution time by transferring data in bursts (그림 3).