// 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;
    assign wren = // fill your code here
    always @(posedge clk) begin
        // fill
        // your
        // code
        // here
    end
    wire start;
    assign start = // fill your code here
    // Read
    reg [31:0] rdata;
    //----------------------------------------------------------
    // 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 : ___----_________________________________
    //
    always @(posedge clk) begin
        // fill
        // your
        // code
        // here
    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



// DMAC/RTL/filelist.f
-sverilog \$LAB_PATH/RTL/DMAC_CFG.sv



// DMAC/SIM/TB/AXI_INTF.sv
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



// DMAC/SIM/TB/DMAC_CFG_TB.sv
`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 10000000
module DMAC_CFG_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));
    reg [31:0] test_vector;
    initial begin
        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(32'h0, data);
        \$display("---------------------------------------------------");
        \$display("IP version: %x", data);
     if (data!=='h0001_2024)
      \$display("Wrong IP version");
  \$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
        \$display("---------------------------------------------------");
        \$display("Configuration test");
        \$display("---------------------------------------------------");
        test_vector = 32'h1000;
        apb_if.write(`SRC_ADDR, test_vector);
        apb_if.read(`SRC_ADDR, data);
        if (data===test_vector)
            \$display("DMA_SRC(pass): %x", data);
        else begin
            \$display("DMA_SRC(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        test_vector = 32'h2000;
        apb_if.write(`DST_ADDR, test_vector);
        apb_if.read(`DST_ADDR, data);
        if (data===test_vector)
            \$display("DMA_DST(pass): %x", data);
        else begin
            \$display("DMA_DST(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        test_vector = 32'h100;
        apb_if.write(`LEN_ADDR, test_vector);
        apb_if.read(`LEN_ADDR, data);
        if (data===test_vector)
            \$display("DMA_LEN(pass): %x", data);
        else begin
            \$display("DMA_LEN(fail): %x", data);
            @(posedge clk);
            \$finish;
        end
        \$display("---------------------------------------------------");
        \$display("DMA start");
        \$display("---------------------------------------------------");
        test_vector = 32'h1;
        apb_if.write(`START_ADDR, test_vector);
        \$display("---------------------------------------------------");
        \$display("Wait for a DMA completion");
        \$display("---------------------------------------------------");
        data = 0;
        while (data != 1) begin
            apb_if.read(`STAT_ADDR, data);
            repeat (100) @(posedge clk);
            \$write(".");
        end
        \$display("");
        @(posedge clk);
        \$display("---------------------------------------------------");
        \$display("DMA completed");
        \$display("---------------------------------------------------");
        \$finish;
    end
    DMAC_CFG 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),
        .src_addr_o (/* FLOATING */),
        .dst_addr_o (/* FLOATING */),
        .byte_len_o (/* FLOATING */),
        .start_o (/* FLOATING */),
        .done_i (1'b1)
    );
endmodule



// DMAC/SIM/TB/filelist.f
-sverilog \$LAB_PATH/SIM/TB/timescale.v
-sverilog \$LAB_PATH/SIM/TB/AXI_INTF.sv
-sverilog \$LAB_PATH/SIM/TB/DMAC_CFG_TB.sv



// DMAC/SIM/TB/timescale.v
`timescale 1ns/1ps