"outstanding_wr_cnt"보다 더 적절한 변수명을 추천해줘. 아래의 코드를 참고하시오.
<<StartOfFile:DMAC/RTLv1/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 [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 [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 [1:0] bresp_i,
    input wire bvalid_i,
    output wire bready_o,
    // AMBA AXI interface (AR channel)
    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 [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,
                                S_WAIT = 3'd5;
    reg [2:0] state, state_n;
    reg [15:0] outstanding_wr_cnt, outstanding_wr_cnt_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;
            outstanding_wr_cnt <= 'd0;
            src_addr <= 32'd0;
            dst_addr <= 32'd0;
            cnt <= 16'd0;
            wcnt <= 4'd0;
        end
        else begin
            state <= state_n;
            outstanding_wr_cnt <= outstanding_wr_cnt_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
        state_n = state;
        src_addr_n = src_addr;
        dst_addr_n = dst_addr;
        cnt_n = cnt;
        wcnt_n = wcnt;
        arvalid = 1'b0;
        rready = 1'b0;
        awvalid = 1'b0;
        wvalid = 1'b0;
        wlast = 1'b0;
        done = 1'b0;
        fifo_wren = 1'b0;
        fifo_rden = 1'b0;
        case (state)
            S_IDLE: begin
                done = 1'b1;
                if (start_i & byte_len_i!=16'd0) 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
                arvalid = 1'b1;
                if (arready_i) begin
                    state_n = S_RDATA;
                    src_addr_n = src_addr + 'd64;
                end
            end
            S_RDATA: begin
                rready = 1'b1;
                if (rvalid_i) begin
                    fifo_wren = 1'b1;
                    if (rlast_i) begin
                        state_n = S_WREQ;
                    end
                end
            end
            S_WREQ: begin
                awvalid = 1'b1;
                if (awready_i) begin
                    state_n = S_WDATA;
                    dst_addr_n = dst_addr + 'd64;
                    wcnt_n = awlen_o;
                    if (cnt>='d64) begin
                        cnt_n = cnt - 'd64;
                    end
                    else begin
                        cnt_n = 'd0;
                    end
                end
            end
            S_WDATA: begin
                wvalid = 1'b1;
                wlast = (wcnt==4'd0);
                if (wready_i) begin
                    fifo_rden = 1'b1;
                    if (wlast) begin
                        if (cnt==16'd0) begin
                            state_n = S_WAIT;
                        end
                        else begin
                            state_n = S_RREQ;
                        end
                    end
                    else begin
                        wcnt_n = wcnt - 4'd1;
                    end
                end
            end
            S_WAIT: begin
                if (outstanding_wr_cnt=='d0) begin
                    state_n = S_IDLE;
                end
            end
        endcase
    end
    wire outstanding_wr_inc = awvalid_o & awready_i;
    wire outstanding_wr_dec = bvalid_i & bready_o & (bresp_i==2'd0);
    always_comb
    begin
        outstanding_wr_cnt_n = outstanding_wr_cnt;
        if (outstanding_wr_inc & !outstanding_wr_dec)
            outstanding_wr_cnt_n = outstanding_wr_cnt + 'd1;
        else if (!outstanding_wr_inc & outstanding_wr_dec)
            outstanding_wr_cnt_n = outstanding_wr_cnt - 'd1;
    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 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 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 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/RTLv1/DMAC_ENGINE.sv>>
<<StartOfFile:DMAC/RTLv1/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/RTLv1/DMAC_CFG.sv>>
<<StartOfFile:DMAC/RTLv1/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] mem[FIFO_DEPTH];
    reg full, full_n,
                                        empty, empty_n;
    reg [DEPTH_LG2:0] wrptr, wrptr_n,
                                        rdptr, rdptr_n;
    always_ff @(posedge clk)
        if (!rst_n) begin
            for (int i=0; i<FIFO_DEPTH; i++) begin
                mem[i] <= {DATA_WIDTH{1'b0}};
            end
        end
        else begin
            if (wren_i) begin
                mem[wrptr[DEPTH_LG2-1:0]] <= wdata_i;
            end
        end
    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}};
        end
        else begin
            full <= full_n;
            empty <= empty_n;
            wrptr <= wrptr_n;
            rdptr <= rdptr_n;
        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 = mem[rdptr[DEPTH_LG2-1:0]];
endmodule
<<EndOfFile:DMAC/RTLv1/DMAC_FIFO.sv>>
<<StartOfFile:DMAC/RTLv1/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)
        .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)
        .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)
        .bresp_i (bresp_i),
        .bvalid_i (bvalid_i),
        .bready_o (bready_o),
        // AMBA AXI interface (AR channel)
        .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)
        .rdata_i (rdata_i),
        .rresp_i (rresp_i),
        .rlast_i (rlast_i),
        .rvalid_i (rvalid_i),
        .rready_o (rready_o)
    );
    assign awid_o = 'd0;
    assign wid_o = 'd0;
    assign arid_o = 'd0;
endmodule
<<EndOfFile:DMAC/RTLv1/DMAC_TOP.sv>>
<<StartOfFile:DMAC/SIMv1/TB/DMAC_TOP_TB.sv>>
`define IP_VER 32'h000
`define CH_SFR_SIZE 32'h100
`define SRC_OFFSET 32'h0
`define DST_OFFSET 32'h4
`define LEN_OFFSET 32'h8
`define CMD_OFFSET 32'hc
`define STAT_OFFSET 32'h10
`define TIMEOUT_DELAY 99999999
`define SRC_REGION_START 32'h0000_0000
`define SRC_REGION_SIZE 32'h0000_2000
`define DST_REGION_STRIDE 32'h0000_2000
`define RANDOM_SEED 12123344
`define TEST_CNT 100
module DMAC_TOP_TB ();
  // inject random seed
  initial begin
    \$srandom(`RANDOM_SEED);
  end
  //----------------------------------------------------------
  // clock and reset generation
  //----------------------------------------------------------
  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
  // timeout
  initial begin
    #`TIMEOUT_DELAY \$display("Timeout!");
    \$finish;
  end
  // enable waveform dump
  initial begin
    \$dumpvars(0, u_DUT);
    \$dumpfile("dump.vcd");
  end
  //----------------------------------------------------------
  // Connection between DUT and test modules
  //----------------------------------------------------------
  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));
  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)
  );
  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)
  );
  //----------------------------------------------------------
  // Testbench starts
  //----------------------------------------------------------
  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("Load data to memory");
    \$display("---------------------------------------------------");
    for (int i=0; i<`SRC_REGION_SIZE; i=i+4) begin
      // write random data
      u_mem.write_word(`SRC_REGION_START+i, \$random);
    end
  endtask
  // this task must be declared automatic so that each invocation uses
  // different memories
  task automatic test_dma(input int ch, input int src, input int dst, input int len);
    int data;
    \$display("Ch[%d] DMA configure %x -> %x (%x)", ch, src, dst, len);
    apb_if.write((ch+1)*`CH_SFR_SIZE+`SRC_OFFSET, src);
    apb_if.read((ch+1)*`CH_SFR_SIZE+`SRC_OFFSET, data);
    if (data!==src) begin
      \$display("DMA_SRC[%d](fail): %x", ch, data);
      @(posedge clk);
      \$finish;
    end
    apb_if.write((ch+1)*`CH_SFR_SIZE+`DST_OFFSET, dst);
    apb_if.read((ch+1)*`CH_SFR_SIZE+`DST_OFFSET, data);
    if (data!==dst) begin
      \$display("DMA_DST[%d](fail): %x", ch, data);
      @(posedge clk);
      \$finish;
    end
    apb_if.write((ch+1)*`CH_SFR_SIZE+`LEN_OFFSET, len);
    apb_if.read((ch+1)*`CH_SFR_SIZE+`LEN_OFFSET, data);
    if (data!==len) begin
      \$display("DMA_LEN[%d](fail): %x", ch, data);
      @(posedge clk);
      \$finish;
    end
    \$display("Ch[%d] DMA start", ch);
    apb_if.write((ch+1)*`CH_SFR_SIZE+`CMD_OFFSET, 32'h1);
    data = 0;
    while (data!=1) begin
      apb_if.read((ch+1)*`CH_SFR_SIZE+`STAT_OFFSET, data);
      repeat (100) @(posedge clk);
      \$display("Ch[%d] Waiting for a DMA completion", ch);
    end
    @(posedge clk);
    \$display("Ch[%d] DMA completed", ch);
    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("Ch[%d] Mismatch! (src:%x @%x, dst:%x @%x", ch, src_word, src+i, dst_word, dst+i);
        @(posedge clk);
        \$finish;
      end
    end
    \$display("Ch[%d] DMA passed", ch);
  endtask
  // this task must be declared automatic so that each invocation uses
  // different memories
  task automatic test_channel(input int ch, input int test_cnt);
    int src_offset, dst_offset, len;
    src_offset = 0;
    dst_offset = 0;
    for (int i=0; i<test_cnt; i++) begin
      len = 'h0100;
      test_dma(ch, `SRC_REGION_START+src_offset, (ch+1)*`DST_REGION_STRIDE+dst_offset, len);
      src_offset = src_offset + len;
      dst_offset = dst_offset + len;
    end
  endtask
  // main
  initial begin
    test_init();
    test_channel(0, `TEST_CNT);
    \$finish;
  end
endmodule
<<EndOfFile:DMAC/SIMv1/TB/DMAC_TOP_TB.sv>>
<<StartOfFile:DMAC/SIMv1/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;
    // a semaphore to allow only one access at a time
    semaphore sema;
    initial begin
        sema = new(1);
    end
    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 automatic write(input int addr,
                         input int data);
        // during a write, another threads cannot access APB
        sema.get(1);
        #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;
        // release the semaphore
        sema.put(1);
    endtask
    task automatic read(input int addr,
                        output int data);
        // during a read, another threads cannot access APB
        sema.get(1);
        #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;
        // release the semaphore
        sema.put(1);
    endtask
endinterface
<<EndOfFile:DMAC/SIMv1/TB/AXI_INTF.sv>>
<<StartOfFile:DMAC/SIMv1/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/SIMv1/TB/AXI_SLAVE.sv>>
<<StartOfFile:DMAC/SIMv1/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/SIMv1/TB/AXI_TYPEDEF.svh>>