The code should now produce the output shown below.  Fill in "FILL YOUR CODE HERE" in "DMAC/RTL/DMAC_ENGINE.sv".

---------------------------------------------------
IP version: 00012024
---------------------------------------------------
---------------------------------------------------
Reset value test
---------------------------------------------------
DMA_SRC(pass): 00000000
DMA_DST(pass): 00000000
DMA_LEN(pass): 00000000
DMA_STATUS(pass): 00000001
===================================================
= 1st trial
= Copying 00000100 bytes from 00001000 to 00002000
===================================================
---------------------------------------------------
Load data to memory
---------------------------------------------------
---------------------------------------------------
Configuration test
---------------------------------------------------
DMA_SRC(pass): 00001000
DMA_DST(pass): 00002000
DMA_LEN(pass): 00000100
---------------------------------------------------
DMA start
---------------------------------------------------
---------------------------------------------------
Wait for a DMA completion
---------------------------------------------------
Timeout!

<<<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
        // ********************** 
        // ********************** 
        // START:FILL YOUR CODE HERE
            state_n = state;
    src_addr_n = src_addr;
    dst_addr_n = dst_addr;
    cnt_n = cnt;
    wcnt_n = wcnt;
    arvalid = 0;
    awvalid = 0;
    wvalid = 0;
    rready = 0;
    fifo_wren = 0;
    fifo_rden = 0;
    done = 0;

    case (state)
        S_IDLE: begin
            done = 1;
            if (start_i) begin
                src_addr_n = src_addr_i;
                dst_addr_n = dst_addr_i;
                cnt_n = byte_len_i;
                state_n = S_RREQ;
            end
        end
        S_RREQ: begin
            if (!arvalid && !fifo_full) begin
                arvalid = 1;
                if (arready_i) state_n = S_RDATA;
            end
        end
        S_RDATA: begin
            if (rvalid_i) begin
                fifo_wren = 1;
                if (rlast_i) state_n = S_WREQ;
            end
            rready = !fifo_full;
        end
        S_WREQ: begin
            if (!awvalid && !fifo_empty) begin
                awvalid = 1;
                if (awready_i) state_n = S_WDATA;
            end
        end
        S_WDATA: begin
            fifo_rden = !fifo_empty;
            wvalid = fifo_rden;
            if (wready_i && wvalid) begin
                wcnt_n = wcnt + 1;
                if (wcnt == awlen_o) begin
                    wlast = 1;
                    if (bvalid_i) begin
                        state_n = S_IDLE;
                        done = 1;
                    end
                end
            end
        end
    endcase

        // END: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>>>



<<<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_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_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>>>