data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v
None: at end of input
1: b'%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:36: Cannot find include file: config.h\n`include "config.h" \n         ^~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA,data/full_repos/permissive/200650987/config.h\n             data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA,data/full_repos/permissive/200650987/config.h.v\n             data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA,data/full_repos/permissive/200650987/config.h.sv\n             config.h\n             config.h.v\n             config.h.sv\n             obj_dir/config.h\n             obj_dir/config.h.v\n             obj_dir/config.h.sv\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:55: Define or directive not defined: \'`LID\'\noutput [`LID         -1 :0] awid;\n        ^~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:56: Define or directive not defined: \'`Lawaddr\'\noutput [`Lawaddr     -1 :0] awaddr;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:57: Define or directive not defined: \'`Lawlen\'\noutput [`Lawlen      -1 :0] awlen;\n        ^~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:58: Define or directive not defined: \'`Lawsize\'\noutput [`Lawsize     -1 :0] awsize;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:59: Define or directive not defined: \'`Lawburst\'\noutput [`Lawburst    -1 :0] awburst;\n        ^~~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:60: Define or directive not defined: \'`Lawlock\'\noutput [`Lawlock     -1 :0] awlock;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:61: Define or directive not defined: \'`Lawcache\'\noutput [`Lawcache    -1 :0] awcache;\n        ^~~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:62: Define or directive not defined: \'`Lawprot\'\noutput [`Lawprot     -1 :0] awprot;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:65: Define or directive not defined: \'`LID\'\noutput [`LID         -1 :0] wid;\n        ^~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:71: Define or directive not defined: \'`LID\'\ninput  [`LID         -1 :0] bid;\n        ^~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:72: Define or directive not defined: \'`Lbresp\'\ninput  [`Lbresp      -1 :0] bresp;\n        ^~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:75: Define or directive not defined: \'`LID\'\noutput [`LID         -1 :0] arid;\n        ^~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:76: Define or directive not defined: \'`Laraddr\'\noutput [`Laraddr     -1 :0] araddr;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:77: Define or directive not defined: \'`Larlen\'\noutput [`Larlen      -1 :0] arlen;\n        ^~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:78: Define or directive not defined: \'`Larsize\'\noutput [`Larsize     -1 :0] arsize;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:79: Define or directive not defined: \'`Larburst\'\noutput [`Larburst    -1 :0] arburst;\n        ^~~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:80: Define or directive not defined: \'`Larlock\'\noutput [`Larlock     -1 :0] arlock;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:81: Define or directive not defined: \'`Larcache\'\noutput [`Larcache    -1 :0] arcache;\n        ^~~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:82: Define or directive not defined: \'`Larprot\'\noutput [`Larprot     -1 :0] arprot;\n        ^~~~~~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:85: Define or directive not defined: \'`LID\'\ninput  [`LID         -1 :0] rid;\n        ^~~~\n%Error: data/full_repos/permissive/200650987/project/display/soc_up/rtl/DMA/dma.v:87: Define or directive not defined: \'`Lrresp\'\ninput  [`Lrresp      -1 :0] rresp;\n        ^~~~~~~\n%Error: Exiting due to 22 error(s)\n'
module dma_master(
               clk,
               rst_n,
               arid, araddr, arlen ,arsize, arburst, arlock, arcache, arprot, arvalid, arready,
               rid , rdata , rresp ,rlast , rvalid , rready,
               awid, awaddr, awlen ,awsize, awburst, awlock, awcache, awprot, awvalid, awready,
               wid , wdata , wstrb ,wlast , wvalid , wready,
               bid , bresp , bvalid,bready, 
               dma_int, order_addr_in,dma_req_in,dma_ack_out,
               finish_read_order, write_dma_end,dma_gnt,
               apb_valid_req,apb_psel, apb_penable, apb_rw, apb_addr,apb_rdata,apb_wdata
               );
input                       clk;
input                       rst_n;
input                       dma_gnt;

output [`LID         -1 :0] awid;
output [`Lawaddr     -1 :0] awaddr;
output [`Lawlen      -1 :0] awlen;
output [`Lawsize     -1 :0] awsize;
output [`Lawburst    -1 :0] awburst;
output [`Lawlock     -1 :0] awlock;
output [`Lawcache    -1 :0] awcache;
output [`Lawprot     -1 :0] awprot;
output                      awvalid;
input                       awready;
output [`LID         -1 :0] wid;
output [64           -1 :0] wdata;
output [8            -1 :0] wstrb;
output                      wlast;
output                      wvalid;
input                       wready;
input  [`LID         -1 :0] bid;
input  [`Lbresp      -1 :0] bresp;
input                       bvalid;
output                      bready;
output [`LID         -1 :0] arid;
output [`Laraddr     -1 :0] araddr;
output [`Larlen      -1 :0] arlen;
output [`Larsize     -1 :0] arsize;
output [`Larburst    -1 :0] arburst;
output [`Larlock     -1 :0] arlock;
output [`Larcache    -1 :0] arcache;
output [`Larprot     -1 :0] arprot;
output                      arvalid;
input                       arready;
input  [`LID         -1 :0] rid;
input  [64           -1 :0] rdata;
input  [`Lrresp      -1 :0] rresp;
input                       rlast;
input                       rvalid;
output                      rready;

output                      dma_int;
output                      dma_ack_out;
input [31:0]                order_addr_in;
input                       dma_req_in;
output                      finish_read_order;
output                      write_dma_end;

output                      apb_psel; 
output                      apb_valid_req; 
output                      apb_penable;
output                      apb_rw; 
output [31:0]               apb_addr;
input  [31:0]               apb_rdata;
output [31:0]               apb_wdata;

wire read_idle;
wire read_ready;
wire get_order;
wire read_order;
wire finish_read_order;
wire r_ddr_wait;
wire read_ddr;
wire read_ddr_end;
wire read_dev;
wire read_dev_end;
wire read_step_end;
wire write_idle;
wire write_ready;
wire w_ddr_wait;
wire write_ddr;
wire write_ddr_end;
wire w_dma_wait;
wire write_dma;
wire write_dma_end ;
wire write_step_end;
wire rresp_ok = (rresp==2'h0); 
wire bresp_ok = (bresp==2'h0);

wire dma_start;
wire dma_stop;
wire ask_valid;
wire [31:0] ask_addr;
wire [ 1:0] device_num_tmp;
assign device_num_tmp = order_addr_in[1:0];                 
assign ask_valid      = order_addr_in[2] ; 
assign dma_start      = order_addr_in[3] ; 
assign dma_stop       = order_addr_in[4] & 
                        (read_ddr_end  | read_dev_end  | read_step_end  | read_idle ) & 
                        (write_ddr_end | write_dma_end | write_step_end | write_idle);
assign ask_addr       = {order_addr_in[31:5], 5'h0};                 

reg [ 3:0]                dma_read_state; 
reg [ 3:0]                dma_write_state; 
reg [31:0]                count_length;
reg [ 4:0]                count_fifo_r;
reg [ 4:0]                count_fifo_w;
reg [ 5:0]                count_fifo;
reg [31:0]                mem [31:0];
reg                       dma_r_w;
reg [31:0]                dma_order_addr;
reg [31:0]                dma_mem_addr;
reg [31:0]                dma_dev_addr;
reg [31:0]                dma_length;
reg [31:0]                dma_step_length;
reg [31:0]                dma_step_times;
reg [31:0]                dma_state_reg;
reg                       dma_get_order;

wire [31:0]mem0  = mem[0];
wire [31:0]mem1  = mem[1];
wire [31:0]mem2  = mem[2];
wire [31:0]mem3  = mem[3];
wire [31:0]mem4  = mem[4];
wire [31:0]mem5  = mem[5];
wire [31:0]mem6  = mem[6];
wire [31:0]mem7  = mem[7];
wire [31:0]mem8  = mem[8];
wire [31:0]mem9  = mem[9];
wire [31:0]mem10 = mem[10];
wire [31:0]mem11 = mem[11];
wire [31:0]mem12 = mem[12];
wire [31:0]mem13 = mem[13];
wire [31:0]mem14 = mem[14];
wire [31:0]mem15 = mem[15];
wire [31:0]mem16 = mem[16];
wire [31:0]mem17 = mem[17];
wire [31:0]mem18 = mem[18];
wire [31:0]mem19 = mem[19];
wire [31:0]mem20 = mem[20];
wire [31:0]mem21 = mem[21];
wire [31:0]mem22 = mem[22];
wire [31:0]mem23 = mem[23];
wire [31:0]mem24 = mem[24];
wire [31:0]mem25 = mem[25];
wire [31:0]mem26 = mem[26];
wire [31:0]mem27 = mem[27];
wire [31:0]mem28 = mem[28];
wire [31:0]mem29 = mem[29];
wire [31:0]mem30 = mem[30];
wire [31:0]mem31 = mem[31];

wire                      dma_order_en;
wire[ 3:0]                dma_next_read_state;
wire[ 3:0]                dma_next_write_state;
wire[31:0]                count_obj;
wire                      dma_single_trans_over;
wire                      dma_trans_over;
wire                      dma_state_change_en;
wire                      dma_int_mask;

assign dma_int_mask = dma_state_reg[0];
assign dma_int      = dma_state_reg[1];
assign dma_order_en = dma_order_addr[0];

reg dma_req_in_reg_1, dma_req_in_reg_2;
reg dma_req_r;
reg dma_req;
always @(posedge clk)begin
    if (~rst_n) begin
        dma_req_in_reg_1 <= 1'b0;
        dma_req_in_reg_2 <= 1'b0;
    end else begin
        dma_req_in_reg_1 <= dma_req_in;
        dma_req_in_reg_2 <= dma_req_in_reg_1;
    end 
end
always @(posedge clk)begin
    if (~rst_n)
        dma_req_r <= 1'b0;
    else
        dma_req_r <= dma_req_in_reg_2;
end
always @(posedge clk)begin
    if (~rst_n)
        dma_req   <= 1'b0;
    else if (dma_ack_out | !dma_req_in_reg_2)
        dma_req   <= 1'b0;
    else if (~dma_req_r & dma_req_in_reg_2)
        dma_req   <= 1'b1;
end

parameter  READ_IDLE            = 4'h0;
parameter  READ_READY           = 4'h1;
parameter  GET_ORDER            = 4'h2;
parameter  READ_ORDER           = 4'h3;
parameter  FINISH_READ_ORDER    = 4'h4;
parameter  R_DDR_WAIT           = 4'h5;
parameter  READ_DDR             = 4'h6;
parameter  READ_DDR_END         = 4'h7;
parameter  READ_DEV             = 4'h8;
parameter  READ_DEV_END         = 4'h9;
parameter  READ_STEP_END        = 4'ha;

assign read_idle                = dma_read_state==READ_IDLE;
assign read_ready               = dma_read_state==READ_READY;
assign get_order                = dma_read_state==GET_ORDER;
assign read_order               = dma_read_state==READ_ORDER;
assign finish_read_order        = dma_read_state==FINISH_READ_ORDER;
assign r_ddr_wait               = dma_read_state==R_DDR_WAIT;
assign read_ddr                 = dma_read_state==READ_DDR;
assign read_ddr_end             = dma_read_state==READ_DDR_END;
assign read_dev                 = dma_read_state==READ_DEV;
assign read_dev_end             = dma_read_state==READ_DEV_END;
assign read_step_end            = dma_read_state==READ_STEP_END;

assign dma_single_trans_over = (write_step_end | read_step_end & (count_fifo==0)) & (count_length==32'b0) & (dma_step_times==32'b1) ? 1'b1 : 1'b0;
assign dma_trans_over        = dma_single_trans_over & !dma_order_en;
reg dma_trans_over_reg;
always @(posedge clk)begin
    if(!rst_n)
        dma_trans_over_reg <= 1'b0;
    else if(dma_trans_over)
        dma_trans_over_reg <= 1'b1;
    else if((read_idle & write_idle) & dma_start)
        dma_trans_over_reg <= 1'b0;
end

wire [5:0] num_fifo;
wire read_ddr_again  = !dma_get_order &  dma_r_w & (count_fifo <= `READ_LENGTH) & (count_length!=0) & (num_fifo >6'h0); 
wire read_dev_again  = !dma_get_order & !dma_r_w & dma_req & (count_fifo < 6'h20);

assign dma_next_read_state  = read_idle         ? (dma_start ? READ_READY : READ_IDLE) :
                              read_ready        ? (dma_get_order ? GET_ORDER : read_ddr_again ? R_DDR_WAIT : read_dev_again ? READ_DEV : READ_READY) :
                              get_order         ? (arready ? READ_ORDER : GET_ORDER) :   
                              read_order        ? (rvalid & rlast & rready & rresp_ok ? FINISH_READ_ORDER : READ_ORDER) : 
                              finish_read_order ?  READ_READY : 
                              r_ddr_wait        ? (arready ? READ_DDR : R_DDR_WAIT) :
                              read_ddr          ? (rvalid & rready & rlast & rresp_ok ? READ_DDR_END : READ_DDR) :
                              read_ddr_end      ? ((count_length==0) ? READ_STEP_END : read_ddr_again ? R_DDR_WAIT : READ_DDR_END) :
                              read_step_end     ? ((dma_trans_over | dma_stop) ? READ_IDLE : dma_get_order ? GET_ORDER : read_ddr_again ? R_DDR_WAIT : READ_STEP_END) :
                              read_dev          ? ((dma_trans_over | dma_stop) ? READ_IDLE : dma_get_order ? GET_ORDER : apb_penable ? READ_DEV_END : READ_DEV) :
                              read_dev_end      ? ((dma_trans_over | dma_stop) ? READ_IDLE : dma_get_order ? GET_ORDER : read_dev_again ? READ_DEV : READ_DEV_END) : READ_IDLE;


reg [1:0]arb_write_op;
wire aw_empty     = (arb_write_op==2'b01) & write_ddr_end || (arb_write_op==2'b00) & write_dma_end || (arb_write_op==2'b11); 
wire write_ddr_ok = ((count_fifo >= `WRITE_LENGTH) | (count_fifo >= count_length)) & (count_length!=0);
always @(posedge clk)begin
    if(!rst_n | dma_stop)
        arb_write_op <= 2'b11;
    else if(ask_valid & aw_empty & (arb_write_op!=0))
        arb_write_op <= 2'b00;
    else if(!dma_r_w & write_ddr_ok & aw_empty)
        arb_write_op <= 2'b01;
    else if(aw_empty)
        arb_write_op <= 2'b11;
end

wire write_ddr_again = !dma_get_order & (arb_write_op==2'b01) & write_ddr_ok;
wire write_dma_again = !dma_get_order & (arb_write_op==2'b00); 

parameter  WRITE_IDLE           = 4'h0;
parameter  W_DDR_WAIT           = 4'h1;
parameter  WRITE_DDR            = 4'h2;
parameter  WRITE_DDR_END        = 4'h3;
parameter  W_DMA_WAIT           = 4'h4;
parameter  WRITE_DMA            = 4'h5;
parameter  WRITE_DMA_END        = 4'h6;
parameter  WRITE_STEP_END       = 4'h7;
assign write_idle               = dma_write_state==WRITE_IDLE;
assign w_ddr_wait               = dma_write_state==W_DDR_WAIT;
assign write_ddr                = dma_write_state==WRITE_DDR;
assign write_ddr_end            = dma_write_state==WRITE_DDR_END;
assign w_dma_wait               = dma_write_state==W_DMA_WAIT;
assign write_dma                = dma_write_state==WRITE_DMA;
assign write_dma_end            = dma_write_state==WRITE_DMA_END;
assign write_step_end           = dma_write_state==WRITE_STEP_END;
reg    awvalid_dma;
assign dma_next_write_state = write_idle          ? (write_dma_again ? W_DMA_WAIT : write_ddr_again ? W_DDR_WAIT : WRITE_IDLE) :
                              w_ddr_wait          ? (awready ? WRITE_DDR : W_DDR_WAIT) :
                              write_ddr           ? (bvalid & bresp_ok & bready ? WRITE_DDR_END : WRITE_DDR) :
                              write_ddr_end       ? (write_dma_again ? W_DMA_WAIT : (count_length==0) ? WRITE_STEP_END : write_ddr_again ? W_DDR_WAIT : WRITE_DDR_END):
                              w_dma_wait          ? (awvalid_dma & awready ? WRITE_DMA : W_DMA_WAIT) :
                              write_dma           ? (bvalid & bresp_ok & bready ? WRITE_DMA_END : WRITE_DMA) :
                              write_dma_end       ? (dma_r_w ? WRITE_IDLE : (count_length==0) ? WRITE_STEP_END : write_ddr_again ? W_DDR_WAIT : WRITE_DMA_END) :
                              write_step_end      ? ((dma_trans_over | dma_stop | (count_length==0)&(dma_step_times==32'h1)) ? WRITE_IDLE :
                                                    write_dma_again ? W_DMA_WAIT : write_ddr_again ? W_DDR_WAIT : WRITE_STEP_END) : WRITE_IDLE;

wire [1:0] ac97_mod = dma_dev_addr[29:28];
wire byte_mod = (ac97_mod == 2'b00);
wire half_mod = (ac97_mod == 2'b01);
wire word_mod = (ac97_mod == 2'b10);
wire [31:0] mem_0          = mem[count_fifo_w];
wire [31:0] mem_1          = mem[count_fifo_w+1];
wire [31:0] wdata_tmp0_tmp = byte_mod ? {mem_1[23:16], mem_1[7 :0], mem_0[23:16], mem_0[7 :0]} : half_mod ? {mem_1[15: 0], mem_0[15: 0]} : mem_0;
wire [31:0] wdata_tmp1_tmp = byte_mod ? {mem_1[31:24], mem_1[15:8], mem_0[31:24], mem_0[15:8]} : half_mod ? {mem_1[31:16], mem_0[31:16]} : mem_1;
wire [31:0] wdata_tmp0     = dma_dev_addr[30] ? wdata_tmp0_tmp : mem_0;
wire [31:0] wdata_tmp1     = dma_dev_addr[30] ? wdata_tmp1_tmp : mem_0;
reg  [32:0] reg_ac97;
wire write_dev_ok = ((dma_dev_addr[31:30]==2'b11) ? (reg_ac97[32] | (count_fifo>=6'h2)) : (count_fifo>=6'h1)) & dma_req & dma_r_w;
always@(posedge clk)begin
    if(!rst_n)
        reg_ac97     <= 33'h0;
    else if(apb_penable & dma_dev_addr[31] & !reg_ac97[32])
        reg_ac97     <= {1'b1, wdata_tmp1};
    else if(apb_penable & reg_ac97[32])
        reg_ac97[32] <= 1'b0;
end

reg arvalid_dev;
always @(posedge clk)begin
    if(!rst_n)
        arvalid_dev <= 1'b0;
    else if(arvalid_dev & apb_penable)
        arvalid_dev <= 1'b0;
    else if((read_dev & !dma_get_order | read_dev_end) & read_dev_again)
        arvalid_dev <= 1'b1;
end

reg awvalid_dev;
always @(posedge clk)begin
    if(!rst_n)
        awvalid_dev <= 1'b0;
    else if(awvalid_dev & apb_penable)
        awvalid_dev <= 1'b0;
    else if(write_dev_ok)
        awvalid_dev <= 1'b1;
end
assign dma_ack_out = apb_psel;  

assign dma_state_change_en  = (dma_read_state !=dma_next_read_state) | (dma_write_state!=dma_next_write_state);
always@(posedge clk)begin
    if(!rst_n | dma_trans_over | dma_stop)begin
        dma_read_state  <= READ_IDLE;
        dma_write_state <= WRITE_IDLE;
    end else if(dma_state_change_en)begin
        dma_read_state  <= dma_next_read_state;
        dma_write_state <= dma_next_write_state;
    end
end

always@(posedge clk)begin
    if(~rst_n | finish_read_order | dma_stop)
        dma_get_order <= 1'b0;
    else if((read_idle & write_idle) & dma_start | dma_single_trans_over & dma_order_en)
        dma_get_order <= 1'b1;
end

wire [2:0] size_tmp   = read_ddr ? arsize : awsize; 
wire [1:0] read_size  = read_dev ? 2'h1 : (arsize==3'h3) ? 2'h2 : 2'h1;                              
wire [1:0] write_size = awvalid_dev ? (((dma_dev_addr[31:30]==2'b11) & (count_fifo>32'h1)) ? 2'h2 : 2'h1) : (awsize==3'h3) ? 2'h2 : 2'h1; 

always@(posedge clk)begin
    if(~rst_n)
        count_length <= 32'b0;             
    else if (dma_stop)
        count_length <= 32'b0;    
    else if(finish_read_order)
        count_length <= dma_length;    
    else if(dma_get_order)
        count_length <= `DMA_ORDERSIZE;    
    else if(((read_ddr_end | write_ddr_end) & count_length==32'b0) & (dma_step_times > 32'h1))
        count_length <= dma_length;
    else if(read_ddr & rvalid & rready & rresp_ok | write_ddr & wvalid & wready)
        count_length <= count_length - ((size_tmp==3'h3) ? 2'h2 : 2'h1);
end

reg [4:0] read_num;
reg [4:0] write_num;
always@(posedge clk)begin
    if(~rst_n | dma_single_trans_over | dma_stop)begin
        count_fifo_r <= 5'h0;
        read_num     <= 5'h0;
    end else if(read_ddr & rvalid & rready & rresp_ok | read_dev & apb_penable)begin
        count_fifo_r <= count_fifo_r + read_size;
        read_num     <= read_ddr ? (rlast ? 5'h0 : read_num + 1'b1) : read_num;
    end
end
always@(posedge clk)begin
    if(~rst_n | dma_single_trans_over | dma_stop)begin
        count_fifo_w <= 5'h0;
        write_num    <= 5'h0;
    end else if(write_ddr & wvalid & wready | awvalid_dev & apb_penable & !reg_ac97[32])begin
        count_fifo_w <= count_fifo_w + write_size;
        write_num    <= write_ddr ? (wlast ? 5'h0 : write_num + 1'b1) : write_num;
    end
end

reg write_dma_to_ddr;
reg [1:0]dma_num;

always@(posedge clk)begin
    if(~rst_n)begin
        dma_num          <= 2'h0;
        write_dma_to_ddr <= 1'h0;
end
    else if(write_dma & wvalid & wready)begin
        dma_num          <= dma_num + 1'b1;
        write_dma_to_ddr <= !write_dma_to_ddr;
end
end

wire [1:0] fifo_read_add  = {2{(read_ddr  & rvalid & rready | read_dev  & apb_penable)}} & read_size;
wire [1:0] fifo_write_sum = {2{(write_ddr & wvalid & wready | awvalid_dev & apb_penable & !reg_ac97[32])}} & write_size;
always@(posedge clk)begin
    if(~rst_n | dma_single_trans_over | dma_stop)
        count_fifo   <= 6'h0;
    else 
        count_fifo   <= count_fifo + fifo_read_add - fifo_write_sum;
end

reg arvalid_dma;
wire [31:0] araddr_dma;
wire [3 :0] arlen_dma;
wire [2 :0] arsize_dma;
reg getting_dma;
always @(posedge clk)begin
    if(!rst_n)begin
        arvalid_dma <= 1'b0;
        getting_dma <= 1'b0;
    end else if(arvalid_dma & arready)
        arvalid_dma <= 1'b0;
    else if(dma_get_order & !getting_dma)begin
        arvalid_dma <= 1'b1;
        getting_dma <= 1'b1;
    end else if(finish_read_order | dma_stop)
        getting_dma <= 1'b0;
end
assign araddr_dma  = (dma_start & dma_get_order) ? ask_addr : {dma_order_addr[31:5], 5'h0};
assign arlen_dma   = 4'h3;
assign arsize_dma  = 3'h3;

wire [2:0] arsize_ddr_tmp;
wire [3:0] arlen_ddr_tmp;
wire [5:0] left_fifo = `DMA_WORDSIZE - count_fifo;
wire       enough_8;
assign num_fifo  = (count_length >= left_fifo) ? left_fifo : count_length;
wire [3:0] arlen_tmp = (num_fifo >= 6'h10) ? 4'hf : (num_fifo-1'b1);  
assign enough_8 = (num_fifo >= 6'h2);
assign arsize_ddr_tmp = (dma_mem_addr[2:0]==3'h0) & enough_8 ? 3'h3 : 3'h2; 
assign arlen_ddr_tmp  = (dma_mem_addr[2:0]==3'h0) & enough_8 ? (num_fifo[5] ? 4'hf : (num_fifo[5:1]-1'b1)): arlen_tmp; 

reg        arvalid_ddr;
reg [31:0] araddr_ddr;
reg [3 :0] arlen_ddr;
reg [2: 0] arsize_ddr;
always @(posedge clk)begin
    if(!rst_n)
        arvalid_ddr <= 1'b0;
    else if(arready & arvalid_ddr)
        arvalid_ddr <= 1'b0;
    else if((read_ready & !dma_get_order | read_ddr_end | read_step_end) & read_ddr_again & !dma_stop)
        arvalid_ddr <= 1'b1;
end

always @(posedge clk)begin
    if(!rst_n)
        begin
        araddr_ddr <= 32'b0;
        arsize_ddr <= 3'b0;
        arlen_ddr  <= 4'b0;
        end
    else if((read_ready & !dma_get_order | read_ddr_end | read_step_end) & read_ddr_again)begin
        araddr_ddr  <= dma_mem_addr;
        arsize_ddr  <= arsize_ddr_tmp;
        arlen_ddr   <= arlen_ddr_tmp;
    end
end

assign arvalid = dma_get_order ? arvalid_dma  : dma_r_w ? arvalid_ddr  : 1'b0;
assign araddr  = dma_get_order ? {32'h0, araddr_dma} : {32'h0, araddr_ddr};
assign arsize  = dma_get_order ? arsize_dma   : arsize_ddr;
assign arlen   = dma_get_order ? arlen_dma    : arlen_ddr;
assign arid    = dma_get_order ? {4'h0, 4'h1} : {4'h0, 4'h2};
assign arburst = 2'h1;
assign arlock  = 2'h0;
assign arprot  = 3'h0;
assign arcache = 4'h0;
assign rready  = 1'h1;

wire[31:0] count_sou;
assign count_sou = araddr_ddr + {read_num, 2'h0};
wire [31:0]read_data_word = !count_sou[2] ? rdata[31:0] : rdata[63:32]; 
                            
integer i;
always@(posedge clk)
begin
    if(~rst_n | dma_stop | dma_single_trans_over)
        begin
            for(i=0;i<=31;i=i+1) mem[i] <= 32'b0;
        end
    else if(read_ddr & rvalid & rready & rresp_ok & arsize==3'h2)
        mem[count_fifo_r] <= read_data_word;
    else if(read_ddr & rvalid & rready & rresp_ok & arsize==3'h3)
         {mem[count_fifo_r+1], mem[count_fifo_r]} <= rdata;
    else if(read_dev & apb_penable) 
         mem[count_fifo_r] <= apb_rdata;
end

reg [1:0]reg_num;
always@(posedge clk)begin
    if(~rst_n | dma_stop)begin
        dma_r_w        <= 1'b0;
        dma_order_addr <= 32'b0;
        dma_mem_addr   <= 32'b0;
        dma_dev_addr   <= 32'b0;
        dma_length     <= 32'b0;
        dma_step_length<= 32'b0;
        dma_step_times <= 32'b0;
        reg_num        <= 2'b0;
    end 
    else begin
        if(read_ddr & rvalid & rready & rresp_ok | write_ddr & wvalid & wready)
            dma_mem_addr   <= dma_mem_addr + ((size_tmp==3'h3) ? 4'h8 : 3'h4); 
        else if((write_ddr_end | read_ddr_end) & (count_length==32'b0) & dma_step_times>32'b1)begin
            dma_step_times <= dma_step_times - 1;
            dma_mem_addr   <= dma_mem_addr + {dma_step_length, 2'h0};
        end else if(read_order & rvalid & rready & rresp_ok & (reg_num==2'h0))begin
            dma_order_addr <= rdata[31 : 0];
            dma_mem_addr   <= rdata[63 :32];
            reg_num        <= reg_num + 1'b1;
        end else if(read_order & rvalid & rready & rresp_ok & (reg_num==2'h1))begin
            dma_dev_addr   <= rdata[31 : 0];
            dma_length     <= rdata[63 :32];
            reg_num        <= reg_num + 1'b1;
        end else if(read_order & rvalid & rready & rresp_ok & (reg_num==2'h2))begin
            dma_step_length<= rdata[31: 0];
            dma_step_times <= rdata[63:32];
            reg_num        <= reg_num + 1'b1;
        end else if(read_order & rvalid & rready & rresp_ok & rlast)begin
            dma_r_w        <= rdata[12];
            reg_num        <= 2'b0;
        end
    end        
end

reg     dma_int_en;
reg     dma_int_i;
always@(posedge clk)begin
    if(~rst_n)
        dma_state_reg  <= 32'b0;
   else if(read_order & rvalid & rready & rresp_ok & rlast)
        dma_state_reg  <= rdata[31:0];
   else if(dma_start == 1'b1)
        dma_state_reg[1] <= 1'b0;
   else if(dma_int_i & dma_int_en)
        dma_state_reg[1] <= 1'b1;
   else if(dma_state_reg[1])
        dma_state_reg[1] <= 1'b0;
end

reg dma_int_tmp;
always@(posedge clk)
begin
    if(!rst_n)
       dma_int_i <= 1'b0;
    else if(dma_single_trans_over & dma_int_mask & !dma_int_i)
       dma_int_i <= 1'b1;
    else if(dma_int_i & dma_int_en)
        dma_int_i <= 1'b0;
end

always@(posedge clk)
begin
    if(!rst_n)
        dma_int_tmp <= 1'b0;
    else 
        dma_int_tmp <= dma_int_i;
end
always@(posedge clk)
begin
    if(!rst_n)
       dma_int_en <= 1'b1;
    else if(dma_int_tmp & dma_int_en)
       dma_int_en <= 1'b0;
    else if(!dma_int_i)
       dma_int_en <= 1'b1;
end

wire [5:0] write_length;
wire       enough_8_1;
wire [2:0] awsize_ddr_tmp;
wire [3:0] awlen_ddr_tmp;
wire [3:0] awlen_tmp;
assign write_length   = (count_fifo >= count_length) ? count_length[5:0] : count_fifo;
assign enough_8_1     = (write_length >= 3'h2);
assign awlen_tmp      = (write_length >= 5'h10) ? 4'hf : (write_length - 1'b1);  
assign awsize_ddr_tmp = (dma_mem_addr[2:0]==3'h0) & enough_8_1 ? 3'h3 : 3'h2; 
assign awlen_ddr_tmp  = (dma_mem_addr[2:0]==3'h0) & enough_8_1 ? (write_length[5]? 4'hf : (write_length[5:1] - 1'b1)) : awlen_tmp; 
reg        awvalid_ddr;
reg [31:0] awaddr_ddr;
reg [3 :0] awlen_ddr;
reg [2 :0] awsize_ddr;
reg        wvalid_ddr;
always @(posedge clk)begin
    if(!rst_n)
        awvalid_ddr <= 1'b0;
    else if(awvalid_ddr & awready)
        awvalid_ddr <= 1'b0;
    else if(write_ddr_again & !write_dma_again & (write_idle | write_ddr_end | write_dma_end | write_step_end) & !dma_stop)
        awvalid_ddr <= 1'b1;
end
always @(posedge clk)begin
    if(!rst_n)
        begin
        awaddr_ddr <= 32'b0;
        awsize_ddr <= 3'b0;
        awlen_ddr  <= 4'b0;
        end
    else if(write_ddr)begin
        awaddr_ddr <= awaddr_ddr;
        awsize_ddr <= awsize_ddr;
        awlen_ddr  <= awlen_ddr;
    end else if(write_ddr_again & !write_dma_again & (write_idle | write_ddr_end | write_dma_end | write_step_end))begin
        awaddr_ddr <= dma_mem_addr;
        awsize_ddr <= awsize_ddr_tmp; 
        awlen_ddr  <= awlen_ddr_tmp;
    end
end
always @(posedge clk)begin
    if(!rst_n)
        wvalid_ddr <= 1'b0;
    else if (awvalid_ddr & awready)begin
        wvalid_ddr <= 1'b1;
    end    
    else if(write_ddr & wvalid & wready)begin
        wvalid_ddr <= !wlast;
    end
end
assign count_obj = awaddr_ddr + {write_num, 2'h0};
wire [63:0] wdata_word = !count_obj[2] ? {32'h0, mem[count_fifo_w]} : {mem[count_fifo_w], 32'h0};
wire [7 :0] wstrb_word = !count_obj[2] ? 8'h0f : 8'hf0; 
wire [63:0] wdata_64   = {mem[count_fifo_w+1], mem[count_fifo_w]};
wire [63:0] wdata_ddr;
wire [15:0] wstrb_ddr;
wire         wlast_ddr;
assign wdata_ddr = (awsize_ddr==3'h2) ? wdata_word : wdata_64;
assign wstrb_ddr = (awsize_ddr==3'h2) ? wstrb_word : 8'hff;
assign wlast_ddr = (write_num==awlen_ddr); 

reg               wvalid_dma;
wire [31:0]       awaddr_dma;
wire [3 :0]       awlen_dma;
wire [2 :0]       awsize_dma;
wire [63:0]       wdata_dma;
wire [15 :0]      wstrb_dma;
wire              wlast_dma;
always @(posedge clk)begin
    if(!rst_n)
        awvalid_dma   <= 1'b0;
    else if(awvalid_dma & awready)
        awvalid_dma   <= 1'b0;
    else if(write_dma_again & !dma_stop & w_dma_wait)
        awvalid_dma   <= 1'b1;
end
always @(posedge clk)begin
    if(!rst_n)
        wvalid_dma    <= 1'b0;
    else if (awvalid_dma & awready)
        wvalid_dma    <= 1'b1;
    else if(write_dma & wvalid & wready)
        wvalid_dma    <= !wlast;
end

wire [63:0] dma_data0;
wire [63:0] dma_data1;
wire [63:0] dma_data2;
wire [63:0] dma_data3;
wire [31:0] dma_state_tmp = {19'h0, dma_r_w, dma_write_state, dma_read_state, dma_trans_over_reg, 
                             dma_single_trans_over, dma_int, dma_int_mask};

assign dma_data0 = {dma_mem_addr,   dma_order_addr };
assign dma_data1 = {dma_length,     dma_dev_addr   };
assign dma_data2 = {dma_step_times, dma_step_length};
assign dma_data3 = {32'h0,          dma_state_tmp  };

assign awaddr_dma  = ask_addr;  
assign awlen_dma   = 4'h3;
assign awsize_dma  = 3'h3;

assign wlast_dma  = (dma_num== 2'h3); 
assign wdata_dma  = (dma_num==2'h0) ? dma_data0 : (dma_num==2'h1) ? dma_data1 : (dma_num==2'h2) ? dma_data2 : dma_data3;
assign wstrb_dma  = (dma_num!=2'h3) ? 8'hff : 8'h0f;

assign awvalid = awvalid_dma | awvalid_ddr ;
assign awaddr  = awvalid_dma ? {32'h0, awaddr_dma} : {32'h0, awaddr_ddr};
assign awlen   = awvalid_dma ? awlen_dma  : awlen_ddr;
assign awsize  = awvalid_dma ? awsize_dma : awsize_ddr; 
assign awid    = awvalid_dma ? {4'h0, 4'h1} : {4'h0, 4'h2};
assign awburst = 2'h1; 
assign awlock  = 2'h0; 
assign awprot  = 3'h0; 
assign awcache = 4'h0; 
assign wvalid  = wvalid_dma | wvalid_ddr ;
assign wid     = wvalid_dma ? {4'h0, 4'h1} :  {4'h0, 4'h2};
assign wdata   = wvalid_dma ? wdata_dma :  wdata_ddr;
assign wstrb   = wvalid_dma ? wstrb_dma :  wstrb_ddr;
assign wlast   = wvalid_dma ? wlast_dma :  wlast_ddr;
assign bready  = 1'b1;

wire apb_valid_req;
reg  apb_psel;
reg  apb_penable;
reg  apb_rw;
wire [31:0]apb_addr;
wire [31:0]apb_wdata;
assign apb_valid_req = arvalid_dev || awvalid_dev ;
assign apb_addr = dma_dev_addr[31] ? (reg_ac97[32] ? {24'h1fe600, dma_dev_addr[15:8]} :{24'h1fe600, dma_dev_addr[7:0]}) : dma_dev_addr; 
assign apb_wdata= reg_ac97[32] ? reg_ac97[31:0] : wdata_tmp0;
always@(posedge clk)
begin
        if(~rst_n)begin
                apb_psel<= 1'b0;
                apb_penable <= 1'b0;
                apb_rw <= 1'b0;
        end
        else begin
                if(dma_gnt) begin
                        if(apb_penable)begin
                               apb_psel <= 1'b0;
                               apb_rw   <= 1'b0;
                               apb_penable <= 1'b0;
                        end else if(arvalid_dev | awvalid_dev) begin
                               apb_psel <= 1'b1;
                               apb_rw   <= awvalid_dev ;
                               apb_penable <= apb_psel;
                        end else
                               apb_penable <= apb_psel;
                 end else begin
                        apb_psel<= 1'b0;
                        apb_penable <= 1'b0;
                        apb_rw <= 1'b0;
                 end
        end
end

endmodule
module dma_master(
               clk,
               rst_n,
               arid, araddr, arlen ,arsize, arburst, arlock, arcache, arprot, arvalid, arready,
               rid , rdata , rresp ,rlast , rvalid , rready,
               awid, awaddr, awlen ,awsize, awburst, awlock, awcache, awprot, awvalid, awready,
               wid , wdata , wstrb ,wlast , wvalid , wready,
               bid , bresp , bvalid,bready, 
               dma_int, order_addr_in,dma_req_in,dma_ack_out,
               finish_read_order, write_dma_end,dma_gnt,
               apb_valid_req,apb_psel, apb_penable, apb_rw, apb_addr,apb_rdata,apb_wdata
               );

input                       clk;
input                       rst_n;
input                       dma_gnt;

output [`LID         -1 :0] awid;
output [`Lawaddr     -1 :0] awaddr;
output [`Lawlen      -1 :0] awlen;
output [`Lawsize     -1 :0] awsize;
output [`Lawburst    -1 :0] awburst;
output [`Lawlock     -1 :0] awlock;
output [`Lawcache    -1 :0] awcache;
output [`Lawprot     -1 :0] awprot;
output                      awvalid;
input                       awready;
output [`LID         -1 :0] wid;
output [64           -1 :0] wdata;
output [8            -1 :0] wstrb;
output                      wlast;
output                      wvalid;
input                       wready;
input  [`LID         -1 :0] bid;
input  [`Lbresp      -1 :0] bresp;
input                       bvalid;
output                      bready;
output [`LID         -1 :0] arid;
output [`Laraddr     -1 :0] araddr;
output [`Larlen      -1 :0] arlen;
output [`Larsize     -1 :0] arsize;
output [`Larburst    -1 :0] arburst;
output [`Larlock     -1 :0] arlock;
output [`Larcache    -1 :0] arcache;
output [`Larprot     -1 :0] arprot;
output                      arvalid;
input                       arready;
input  [`LID         -1 :0] rid;
input  [64           -1 :0] rdata;
input  [`Lrresp      -1 :0] rresp;
input                       rlast;
input                       rvalid;
output                      rready;

output                      dma_int;
output                      dma_ack_out;
input [31:0]                order_addr_in;
input                       dma_req_in;
output                      finish_read_order;
output                      write_dma_end;

output                      apb_psel; 
output                      apb_valid_req; 
output                      apb_penable;
output                      apb_rw; 
output [31:0]               apb_addr;
input  [31:0]               apb_rdata;
output [31:0]               apb_wdata;

wire read_idle;
wire read_ready;
wire get_order;
wire read_order;
wire finish_read_order;
wire r_ddr_wait;
wire read_ddr;
wire read_ddr_end;
wire read_dev;
wire read_dev_end;
wire read_step_end;
wire write_idle;
wire write_ready;
wire w_ddr_wait;
wire write_ddr;
wire write_ddr_end;
wire w_dma_wait;
wire write_dma;
wire write_dma_end ;
wire write_step_end;
wire rresp_ok = (rresp==2'h0); 
wire bresp_ok = (bresp==2'h0);

wire dma_start;
wire dma_stop;
wire ask_valid;
wire [31:0] ask_addr;
wire [ 1:0] device_num_tmp;
assign device_num_tmp = order_addr_in[1:0];                 
assign ask_valid      = order_addr_in[2] ; 
assign dma_start      = order_addr_in[3] ; 
assign dma_stop       = order_addr_in[4] & 
                        (read_ddr_end  | read_dev_end  | read_step_end  | read_idle ) & 
                        (write_ddr_end | write_dma_end | write_step_end | write_idle);
assign ask_addr       = {order_addr_in[31:5], 5'h0};                 

reg [ 3:0]                dma_read_state; 
reg [ 3:0]                dma_write_state; 
reg [31:0]                count_length;
reg [ 4:0]                count_fifo_r;
reg [ 4:0]                count_fifo_w;
reg [ 5:0]                count_fifo;
reg [31:0]                mem [31:0];
reg                       dma_r_w;
reg [31:0]                dma_order_addr;
reg [31:0]                dma_mem_addr;
reg [31:0]                dma_dev_addr;
reg [31:0]                dma_length;
reg [31:0]                dma_step_length;
reg [31:0]                dma_step_times;
reg [31:0]                dma_state_reg;
reg                       dma_get_order;

wire [31:0]mem0  = mem[0];
wire [31:0]mem1  = mem[1];
wire [31:0]mem2  = mem[2];
wire [31:0]mem3  = mem[3];
wire [31:0]mem4  = mem[4];
wire [31:0]mem5  = mem[5];
wire [31:0]mem6  = mem[6];
wire [31:0]mem7  = mem[7];
wire [31:0]mem8  = mem[8];
wire [31:0]mem9  = mem[9];
wire [31:0]mem10 = mem[10];
wire [31:0]mem11 = mem[11];
wire [31:0]mem12 = mem[12];
wire [31:0]mem13 = mem[13];
wire [31:0]mem14 = mem[14];
wire [31:0]mem15 = mem[15];
wire [31:0]mem16 = mem[16];
wire [31:0]mem17 = mem[17];
wire [31:0]mem18 = mem[18];
wire [31:0]mem19 = mem[19];
wire [31:0]mem20 = mem[20];
wire [31:0]mem21 = mem[21];
wire [31:0]mem22 = mem[22];
wire [31:0]mem23 = mem[23];
wire [31:0]mem24 = mem[24];
wire [31:0]mem25 = mem[25];
wire [31:0]mem26 = mem[26];
wire [31:0]mem27 = mem[27];
wire [31:0]mem28 = mem[28];
wire [31:0]mem29 = mem[29];
wire [31:0]mem30 = mem[30];
wire [31:0]mem31 = mem[31];

wire                      dma_order_en;
wire[ 3:0]                dma_next_read_state;
wire[ 3:0]                dma_next_write_state;
wire[31:0]                count_obj;
wire                      dma_single_trans_over;
wire                      dma_trans_over;
wire                      dma_state_change_en;
wire                      dma_int_mask;

assign dma_int_mask = dma_state_reg[0];
assign dma_int      = dma_state_reg[1];
assign dma_order_en = dma_order_addr[0];

reg dma_req_in_reg_1, dma_req_in_reg_2;
reg dma_req_r;
reg dma_req;
always @(posedge clk)begin
    if (~rst_n) begin
        dma_req_in_reg_1 <= 1'b0;
        dma_req_in_reg_2 <= 1'b0;
    end else begin
        dma_req_in_reg_1 <= dma_req_in;
        dma_req_in_reg_2 <= dma_req_in_reg_1;
    end 
end
always @(posedge clk)begin
    if (~rst_n)
        dma_req_r <= 1'b0;
    else
        dma_req_r <= dma_req_in_reg_2;
end
always @(posedge clk)begin
    if (~rst_n)
        dma_req   <= 1'b0;
    else if (dma_ack_out | !dma_req_in_reg_2)
        dma_req   <= 1'b0;
    else if (~dma_req_r & dma_req_in_reg_2)
        dma_req   <= 1'b1;
end

parameter  READ_IDLE            = 4'h0;
parameter  READ_READY           = 4'h1;
parameter  GET_ORDER            = 4'h2;
parameter  READ_ORDER           = 4'h3;
parameter  FINISH_READ_ORDER    = 4'h4;
parameter  R_DDR_WAIT           = 4'h5;
parameter  READ_DDR             = 4'h6;
parameter  READ_DDR_END         = 4'h7;
parameter  READ_DEV             = 4'h8;
parameter  READ_DEV_END         = 4'h9;
parameter  READ_STEP_END        = 4'ha;

assign read_idle                = dma_read_state==READ_IDLE;
assign read_ready               = dma_read_state==READ_READY;
assign get_order                = dma_read_state==GET_ORDER;
assign read_order               = dma_read_state==READ_ORDER;
assign finish_read_order        = dma_read_state==FINISH_READ_ORDER;
assign r_ddr_wait               = dma_read_state==R_DDR_WAIT;
assign read_ddr                 = dma_read_state==READ_DDR;
assign read_ddr_end             = dma_read_state==READ_DDR_END;
assign read_dev                 = dma_read_state==READ_DEV;
assign read_dev_end             = dma_read_state==READ_DEV_END;
assign read_step_end            = dma_read_state==READ_STEP_END;

assign dma_single_trans_over = (write_step_end | read_step_end & (count_fifo==0)) & (count_length==32'b0) & (dma_step_times==32'b1) ? 1'b1 : 1'b0;
assign dma_trans_over        = dma_single_trans_over & !dma_order_en;
reg dma_trans_over_reg;
always @(posedge clk)begin
    if(!rst_n)
        dma_trans_over_reg <= 1'b0;
    else if(dma_trans_over)
        dma_trans_over_reg <= 1'b1;
    else if((read_idle & write_idle) & dma_start)
        dma_trans_over_reg <= 1'b0;
end

wire [5:0] num_fifo;
wire read_ddr_again  = !dma_get_order &  dma_r_w & (count_fifo <= `READ_LENGTH) & (count_length!=0) & (num_fifo >6'h0); 
wire read_dev_again  = !dma_get_order & !dma_r_w & dma_req & (count_fifo < 6'h20);

assign dma_next_read_state  = read_idle         ? (dma_start ? READ_READY : READ_IDLE) :
                              read_ready        ? (dma_get_order ? GET_ORDER : read_ddr_again ? R_DDR_WAIT : read_dev_again ? READ_DEV : READ_READY) :
                              get_order         ? (arready ? READ_ORDER : GET_ORDER) :   
                              read_order        ? (rvalid & rlast & rready & rresp_ok ? FINISH_READ_ORDER : READ_ORDER) : 
                              finish_read_order ?  READ_READY : 
                              r_ddr_wait        ? (arready ? READ_DDR : R_DDR_WAIT) :
                              read_ddr          ? (rvalid & rready & rlast & rresp_ok ? READ_DDR_END : READ_DDR) :
                              read_ddr_end      ? ((count_length==0) ? READ_STEP_END : read_ddr_again ? R_DDR_WAIT : READ_DDR_END) :
                              read_step_end     ? ((dma_trans_over | dma_stop) ? READ_IDLE : dma_get_order ? GET_ORDER : read_ddr_again ? R_DDR_WAIT : READ_STEP_END) :
                              read_dev          ? ((dma_trans_over | dma_stop) ? READ_IDLE : dma_get_order ? GET_ORDER : apb_penable ? READ_DEV_END : READ_DEV) :
                              read_dev_end      ? ((dma_trans_over | dma_stop) ? READ_IDLE : dma_get_order ? GET_ORDER : read_dev_again ? READ_DEV : READ_DEV_END) : READ_IDLE;


reg [1:0]arb_write_op;
wire aw_empty     = (arb_write_op==2'b01) & write_ddr_end || (arb_write_op==2'b00) & write_dma_end || (arb_write_op==2'b11); 
wire write_ddr_ok = ((count_fifo >= `WRITE_LENGTH) | (count_fifo >= count_length)) & (count_length!=0);
always @(posedge clk)begin
    if(!rst_n | dma_stop)
        arb_write_op <= 2'b11;
    else if(ask_valid & aw_empty & (arb_write_op!=0))
        arb_write_op <= 2'b00;
    else if(!dma_r_w & write_ddr_ok & aw_empty)
        arb_write_op <= 2'b01;
    else if(aw_empty)
        arb_write_op <= 2'b11;
end

wire write_ddr_again = !dma_get_order & (arb_write_op==2'b01) & write_ddr_ok;
wire write_dma_again = !dma_get_order & (arb_write_op==2'b00); 

parameter  WRITE_IDLE           = 4'h0;
parameter  W_DDR_WAIT           = 4'h1;
parameter  WRITE_DDR            = 4'h2;
parameter  WRITE_DDR_END        = 4'h3;
parameter  W_DMA_WAIT           = 4'h4;
parameter  WRITE_DMA            = 4'h5;
parameter  WRITE_DMA_END        = 4'h6;
parameter  WRITE_STEP_END       = 4'h7;
assign write_idle               = dma_write_state==WRITE_IDLE;
assign w_ddr_wait               = dma_write_state==W_DDR_WAIT;
assign write_ddr                = dma_write_state==WRITE_DDR;
assign write_ddr_end            = dma_write_state==WRITE_DDR_END;
assign w_dma_wait               = dma_write_state==W_DMA_WAIT;
assign write_dma                = dma_write_state==WRITE_DMA;
assign write_dma_end            = dma_write_state==WRITE_DMA_END;
assign write_step_end           = dma_write_state==WRITE_STEP_END;
reg    awvalid_dma;
assign dma_next_write_state = write_idle          ? (write_dma_again ? W_DMA_WAIT : write_ddr_again ? W_DDR_WAIT : WRITE_IDLE) :
                              w_ddr_wait          ? (awready ? WRITE_DDR : W_DDR_WAIT) :
                              write_ddr           ? (bvalid & bresp_ok & bready ? WRITE_DDR_END : WRITE_DDR) :
                              write_ddr_end       ? (write_dma_again ? W_DMA_WAIT : (count_length==0) ? WRITE_STEP_END : write_ddr_again ? W_DDR_WAIT : WRITE_DDR_END):
                              w_dma_wait          ? (awvalid_dma & awready ? WRITE_DMA : W_DMA_WAIT) :
                              write_dma           ? (bvalid & bresp_ok & bready ? WRITE_DMA_END : WRITE_DMA) :
                              write_dma_end       ? (dma_r_w ? WRITE_IDLE : (count_length==0) ? WRITE_STEP_END : write_ddr_again ? W_DDR_WAIT : WRITE_DMA_END) :
                              write_step_end      ? ((dma_trans_over | dma_stop | (count_length==0)&(dma_step_times==32'h1)) ? WRITE_IDLE :
                                                    write_dma_again ? W_DMA_WAIT : write_ddr_again ? W_DDR_WAIT : WRITE_STEP_END) : WRITE_IDLE;

wire [1:0] ac97_mod = dma_dev_addr[29:28];
wire byte_mod = (ac97_mod == 2'b00);
wire half_mod = (ac97_mod == 2'b01);
wire word_mod = (ac97_mod == 2'b10);
wire [31:0] mem_0          = mem[count_fifo_w];
wire [31:0] mem_1          = mem[count_fifo_w+1];
wire [31:0] wdata_tmp0_tmp = byte_mod ? {mem_1[23:16], mem_1[7 :0], mem_0[23:16], mem_0[7 :0]} : half_mod ? {mem_1[15: 0], mem_0[15: 0]} : mem_0;
wire [31:0] wdata_tmp1_tmp = byte_mod ? {mem_1[31:24], mem_1[15:8], mem_0[31:24], mem_0[15:8]} : half_mod ? {mem_1[31:16], mem_0[31:16]} : mem_1;
wire [31:0] wdata_tmp0     = dma_dev_addr[30] ? wdata_tmp0_tmp : mem_0;
wire [31:0] wdata_tmp1     = dma_dev_addr[30] ? wdata_tmp1_tmp : mem_0;
reg  [32:0] reg_ac97;
wire write_dev_ok = ((dma_dev_addr[31:30]==2'b11) ? (reg_ac97[32] | (count_fifo>=6'h2)) : (count_fifo>=6'h1)) & dma_req & dma_r_w;
always@(posedge clk)begin
    if(!rst_n)
        reg_ac97     <= 33'h0;
    else if(apb_penable & dma_dev_addr[31] & !reg_ac97[32])
        reg_ac97     <= {1'b1, wdata_tmp1};
    else if(apb_penable & reg_ac97[32])
        reg_ac97[32] <= 1'b0;
end

reg arvalid_dev;
always @(posedge clk)begin
    if(!rst_n)
        arvalid_dev <= 1'b0;
    else if(arvalid_dev & apb_penable)
        arvalid_dev <= 1'b0;
    else if((read_dev & !dma_get_order | read_dev_end) & read_dev_again)
        arvalid_dev <= 1'b1;
end

reg awvalid_dev;
always @(posedge clk)begin
    if(!rst_n)
        awvalid_dev <= 1'b0;
    else if(awvalid_dev & apb_penable)
        awvalid_dev <= 1'b0;
    else if(write_dev_ok)
        awvalid_dev <= 1'b1;
end
assign dma_ack_out = apb_psel;  

assign dma_state_change_en  = (dma_read_state !=dma_next_read_state) | (dma_write_state!=dma_next_write_state);
always@(posedge clk)begin
    if(!rst_n | dma_trans_over | dma_stop)begin
        dma_read_state  <= READ_IDLE;
        dma_write_state <= WRITE_IDLE;
    end else if(dma_state_change_en)begin
        dma_read_state  <= dma_next_read_state;
        dma_write_state <= dma_next_write_state;
    end
end

always@(posedge clk)begin
    if(~rst_n | finish_read_order | dma_stop)
        dma_get_order <= 1'b0;
    else if((read_idle & write_idle) & dma_start | dma_single_trans_over & dma_order_en)
        dma_get_order <= 1'b1;
end

wire [2:0] size_tmp   = read_ddr ? arsize : awsize; 
wire [1:0] read_size  = read_dev ? 2'h1 : (arsize==3'h3) ? 2'h2 : 2'h1;                              
wire [1:0] write_size = awvalid_dev ? (((dma_dev_addr[31:30]==2'b11) & (count_fifo>32'h1)) ? 2'h2 : 2'h1) : (awsize==3'h3) ? 2'h2 : 2'h1; 

always@(posedge clk)begin
    if(~rst_n)
        count_length <= 32'b0;             
    else if (dma_stop)
        count_length <= 32'b0;    
    else if(finish_read_order)
        count_length <= dma_length;    
    else if(dma_get_order)
        count_length <= `DMA_ORDERSIZE;    
    else if(((read_ddr_end | write_ddr_end) & count_length==32'b0) & (dma_step_times > 32'h1))
        count_length <= dma_length;
    else if(read_ddr & rvalid & rready & rresp_ok | write_ddr & wvalid & wready)
        count_length <= count_length - ((size_tmp==3'h3) ? 2'h2 : 2'h1);
end

reg [4:0] read_num;
reg [4:0] write_num;
always@(posedge clk)begin
    if(~rst_n | dma_single_trans_over | dma_stop)begin
        count_fifo_r <= 5'h0;
        read_num     <= 5'h0;
    end else if(read_ddr & rvalid & rready & rresp_ok | read_dev & apb_penable)begin
        count_fifo_r <= count_fifo_r + read_size;
        read_num     <= read_ddr ? (rlast ? 5'h0 : read_num + 1'b1) : read_num;
    end
end
always@(posedge clk)begin
    if(~rst_n | dma_single_trans_over | dma_stop)begin
        count_fifo_w <= 5'h0;
        write_num    <= 5'h0;
    end else if(write_ddr & wvalid & wready | awvalid_dev & apb_penable & !reg_ac97[32])begin
        count_fifo_w <= count_fifo_w + write_size;
        write_num    <= write_ddr ? (wlast ? 5'h0 : write_num + 1'b1) : write_num;
    end
end

reg write_dma_to_ddr;
reg [1:0]dma_num;

always@(posedge clk)begin
    if(~rst_n)begin
        dma_num          <= 2'h0;
        write_dma_to_ddr <= 1'h0;
end
    else if(write_dma & wvalid & wready)begin
        dma_num          <= dma_num + 1'b1;
        write_dma_to_ddr <= !write_dma_to_ddr;
end
end

wire [1:0] fifo_read_add  = {2{(read_ddr  & rvalid & rready | read_dev  & apb_penable)}} & read_size;
wire [1:0] fifo_write_sum = {2{(write_ddr & wvalid & wready | awvalid_dev & apb_penable & !reg_ac97[32])}} & write_size;
always@(posedge clk)begin
    if(~rst_n | dma_single_trans_over | dma_stop)
        count_fifo   <= 6'h0;
    else 
        count_fifo   <= count_fifo + fifo_read_add - fifo_write_sum;
end

reg arvalid_dma;
wire [31:0] araddr_dma;
wire [3 :0] arlen_dma;
wire [2 :0] arsize_dma;
reg getting_dma;
always @(posedge clk)begin
    if(!rst_n)begin
        arvalid_dma <= 1'b0;
        getting_dma <= 1'b0;
    end else if(arvalid_dma & arready)
        arvalid_dma <= 1'b0;
    else if(dma_get_order & !getting_dma)begin
        arvalid_dma <= 1'b1;
        getting_dma <= 1'b1;
    end else if(finish_read_order | dma_stop)
        getting_dma <= 1'b0;
end
assign araddr_dma  = (dma_start & dma_get_order) ? ask_addr : {dma_order_addr[31:5], 5'h0};
assign arlen_dma   = 4'h3;
assign arsize_dma  = 3'h3;

wire [2:0] arsize_ddr_tmp;
wire [3:0] arlen_ddr_tmp;
wire [5:0] left_fifo = `DMA_WORDSIZE - count_fifo;
wire       enough_8;
assign num_fifo  = (count_length >= left_fifo) ? left_fifo : count_length;
wire [3:0] arlen_tmp = (num_fifo >= 6'h10) ? 4'hf : (num_fifo-1'b1);  
assign enough_8 = (num_fifo >= 6'h2);
assign arsize_ddr_tmp = (dma_mem_addr[2:0]==3'h0) & enough_8 ? 3'h3 : 3'h2; 
assign arlen_ddr_tmp  = (dma_mem_addr[2:0]==3'h0) & enough_8 ? (num_fifo[5] ? 4'hf : (num_fifo[5:1]-1'b1)): arlen_tmp; 

reg        arvalid_ddr;
reg [31:0] araddr_ddr;
reg [3 :0] arlen_ddr;
reg [2: 0] arsize_ddr;
always @(posedge clk)begin
    if(!rst_n)
        arvalid_ddr <= 1'b0;
    else if(arready & arvalid_ddr)
        arvalid_ddr <= 1'b0;
    else if((read_ready & !dma_get_order | read_ddr_end | read_step_end) & read_ddr_again & !dma_stop)
        arvalid_ddr <= 1'b1;
end

always @(posedge clk)begin
    if(!rst_n)
        begin
        araddr_ddr <= 32'b0;
        arsize_ddr <= 3'b0;
        arlen_ddr  <= 4'b0;
        end
    else if((read_ready & !dma_get_order | read_ddr_end | read_step_end) & read_ddr_again)begin
        araddr_ddr  <= dma_mem_addr;
        arsize_ddr  <= arsize_ddr_tmp;
        arlen_ddr   <= arlen_ddr_tmp;
    end
end

assign arvalid = dma_get_order ? arvalid_dma  : dma_r_w ? arvalid_ddr  : 1'b0;
assign araddr  = dma_get_order ? {32'h0, araddr_dma} : {32'h0, araddr_ddr};
assign arsize  = dma_get_order ? arsize_dma   : arsize_ddr;
assign arlen   = dma_get_order ? arlen_dma    : arlen_ddr;
assign arid    = dma_get_order ? {4'h0, 4'h1} : {4'h0, 4'h2};
assign arburst = 2'h1;
assign arlock  = 2'h0;
assign arprot  = 3'h0;
assign arcache = 4'h0;
assign rready  = 1'h1;

wire[31:0] count_sou;
assign count_sou = araddr_ddr + {read_num, 2'h0};
wire [31:0]read_data_word = !count_sou[2] ? rdata[31:0] : rdata[63:32]; 
                            
integer i;
always@(posedge clk)
begin
    if(~rst_n | dma_stop | dma_single_trans_over)
        begin
            for(i=0;i<=31;i=i+1) mem[i] <= 32'b0;
        end
    else if(read_ddr & rvalid & rready & rresp_ok & arsize==3'h2)
        mem[count_fifo_r] <= read_data_word;
    else if(read_ddr & rvalid & rready & rresp_ok & arsize==3'h3)
         {mem[count_fifo_r+1], mem[count_fifo_r]} <= rdata;
    else if(read_dev & apb_penable) 
         mem[count_fifo_r] <= apb_rdata;
end

reg [1:0]reg_num;
always@(posedge clk)begin
    if(~rst_n | dma_stop)begin
        dma_r_w        <= 1'b0;
        dma_order_addr <= 32'b0;
        dma_mem_addr   <= 32'b0;
        dma_dev_addr   <= 32'b0;
        dma_length     <= 32'b0;
        dma_step_length<= 32'b0;
        dma_step_times <= 32'b0;
        reg_num        <= 2'b0;
    end 
    else begin
        if(read_ddr & rvalid & rready & rresp_ok | write_ddr & wvalid & wready)
            dma_mem_addr   <= dma_mem_addr + ((size_tmp==3'h3) ? 4'h8 : 3'h4); 
        else if((write_ddr_end | read_ddr_end) & (count_length==32'b0) & dma_step_times>32'b1)begin
            dma_step_times <= dma_step_times - 1;
            dma_mem_addr   <= dma_mem_addr + {dma_step_length, 2'h0};
        end else if(read_order & rvalid & rready & rresp_ok & (reg_num==2'h0))begin
            dma_order_addr <= rdata[31 : 0];
            dma_mem_addr   <= rdata[63 :32];
            reg_num        <= reg_num + 1'b1;
        end else if(read_order & rvalid & rready & rresp_ok & (reg_num==2'h1))begin
            dma_dev_addr   <= rdata[31 : 0];
            dma_length     <= rdata[63 :32];
            reg_num        <= reg_num + 1'b1;
        end else if(read_order & rvalid & rready & rresp_ok & (reg_num==2'h2))begin
            dma_step_length<= rdata[31: 0];
            dma_step_times <= rdata[63:32];
            reg_num        <= reg_num + 1'b1;
        end else if(read_order & rvalid & rready & rresp_ok & rlast)begin
            dma_r_w        <= rdata[12];
            reg_num        <= 2'b0;
        end
    end        
end

reg     dma_int_en;
reg     dma_int_i;
always@(posedge clk)begin
    if(~rst_n)
        dma_state_reg  <= 32'b0;
   else if(read_order & rvalid & rready & rresp_ok & rlast)
        dma_state_reg  <= rdata[31:0];
   else if(dma_start == 1'b1)
        dma_state_reg[1] <= 1'b0;
   else if(dma_int_i & dma_int_en)
        dma_state_reg[1] <= 1'b1;
   else if(dma_state_reg[1])
        dma_state_reg[1] <= 1'b0;
end

reg dma_int_tmp;
always@(posedge clk)
begin
    if(!rst_n)
       dma_int_i <= 1'b0;
    else if(dma_single_trans_over & dma_int_mask & !dma_int_i)
       dma_int_i <= 1'b1;
    else if(dma_int_i & dma_int_en)
        dma_int_i <= 1'b0;
end

always@(posedge clk)
begin
    if(!rst_n)
        dma_int_tmp <= 1'b0;
    else 
        dma_int_tmp <= dma_int_i;
end
always@(posedge clk)
begin
    if(!rst_n)
       dma_int_en <= 1'b1;
    else if(dma_int_tmp & dma_int_en)
       dma_int_en <= 1'b0;
    else if(!dma_int_i)
       dma_int_en <= 1'b1;
end

wire [5:0] write_length;
wire       enough_8_1;
wire [2:0] awsize_ddr_tmp;
wire [3:0] awlen_ddr_tmp;
wire [3:0] awlen_tmp;
assign write_length   = (count_fifo >= count_length) ? count_length[5:0] : count_fifo;
assign enough_8_1     = (write_length >= 3'h2);
assign awlen_tmp      = (write_length >= 5'h10) ? 4'hf : (write_length - 1'b1);  
assign awsize_ddr_tmp = (dma_mem_addr[2:0]==3'h0) & enough_8_1 ? 3'h3 : 3'h2; 
assign awlen_ddr_tmp  = (dma_mem_addr[2:0]==3'h0) & enough_8_1 ? (write_length[5]? 4'hf : (write_length[5:1] - 1'b1)) : awlen_tmp; 
reg        awvalid_ddr;
reg [31:0] awaddr_ddr;
reg [3 :0] awlen_ddr;
reg [2 :0] awsize_ddr;
reg        wvalid_ddr;
always @(posedge clk)begin
    if(!rst_n)
        awvalid_ddr <= 1'b0;
    else if(awvalid_ddr & awready)
        awvalid_ddr <= 1'b0;
    else if(write_ddr_again & !write_dma_again & (write_idle | write_ddr_end | write_dma_end | write_step_end) & !dma_stop)
        awvalid_ddr <= 1'b1;
end
always @(posedge clk)begin
    if(!rst_n)
        begin
        awaddr_ddr <= 32'b0;
        awsize_ddr <= 3'b0;
        awlen_ddr  <= 4'b0;
        end
    else if(write_ddr)begin
        awaddr_ddr <= awaddr_ddr;
        awsize_ddr <= awsize_ddr;
        awlen_ddr  <= awlen_ddr;
    end else if(write_ddr_again & !write_dma_again & (write_idle | write_ddr_end | write_dma_end | write_step_end))begin
        awaddr_ddr <= dma_mem_addr;
        awsize_ddr <= awsize_ddr_tmp; 
        awlen_ddr  <= awlen_ddr_tmp;
    end
end
always @(posedge clk)begin
    if(!rst_n)
        wvalid_ddr <= 1'b0;
    else if (awvalid_ddr & awready)begin
        wvalid_ddr <= 1'b1;
    end    
    else if(write_ddr & wvalid & wready)begin
        wvalid_ddr <= !wlast;
    end
end
assign count_obj = awaddr_ddr + {write_num, 2'h0};
wire [63:0] wdata_word = !count_obj[2] ? {32'h0, mem[count_fifo_w]} : {mem[count_fifo_w], 32'h0};
wire [7 :0] wstrb_word = !count_obj[2] ? 8'h0f : 8'hf0; 
wire [63:0] wdata_64   = {mem[count_fifo_w+1], mem[count_fifo_w]};
wire [63:0] wdata_ddr;
wire [15:0] wstrb_ddr;
wire         wlast_ddr;
assign wdata_ddr = (awsize_ddr==3'h2) ? wdata_word : wdata_64;
assign wstrb_ddr = (awsize_ddr==3'h2) ? wstrb_word : 8'hff;
assign wlast_ddr = (write_num==awlen_ddr); 

reg               wvalid_dma;
wire [31:0]       awaddr_dma;
wire [3 :0]       awlen_dma;
wire [2 :0]       awsize_dma;
wire [63:0]       wdata_dma;
wire [15 :0]      wstrb_dma;
wire              wlast_dma;
always @(posedge clk)begin
    if(!rst_n)
        awvalid_dma   <= 1'b0;
    else if(awvalid_dma & awready)
        awvalid_dma   <= 1'b0;
    else if(write_dma_again & !dma_stop & w_dma_wait)
        awvalid_dma   <= 1'b1;
end
always @(posedge clk)begin
    if(!rst_n)
        wvalid_dma    <= 1'b0;
    else if (awvalid_dma & awready)
        wvalid_dma    <= 1'b1;
    else if(write_dma & wvalid & wready)
        wvalid_dma    <= !wlast;
end

wire [63:0] dma_data0;
wire [63:0] dma_data1;
wire [63:0] dma_data2;
wire [63:0] dma_data3;
wire [31:0] dma_state_tmp = {19'h0, dma_r_w, dma_write_state, dma_read_state, dma_trans_over_reg, 
                             dma_single_trans_over, dma_int, dma_int_mask};

assign dma_data0 = {dma_mem_addr,   dma_order_addr };
assign dma_data1 = {dma_length,     dma_dev_addr   };
assign dma_data2 = {dma_step_times, dma_step_length};
assign dma_data3 = {32'h0,          dma_state_tmp  };

assign awaddr_dma  = ask_addr;  
assign awlen_dma   = 4'h3;
assign awsize_dma  = 3'h3;

assign wlast_dma  = (dma_num== 2'h3); 
assign wdata_dma  = (dma_num==2'h0) ? dma_data0 : (dma_num==2'h1) ? dma_data1 : (dma_num==2'h2) ? dma_data2 : dma_data3;
assign wstrb_dma  = (dma_num!=2'h3) ? 8'hff : 8'h0f;

assign awvalid = awvalid_dma | awvalid_ddr ;
assign awaddr  = awvalid_dma ? {32'h0, awaddr_dma} : {32'h0, awaddr_ddr};
assign awlen   = awvalid_dma ? awlen_dma  : awlen_ddr;
assign awsize  = awvalid_dma ? awsize_dma : awsize_ddr; 
assign awid    = awvalid_dma ? {4'h0, 4'h1} : {4'h0, 4'h2};
assign awburst = 2'h1; 
assign awlock  = 2'h0; 
assign awprot  = 3'h0; 
assign awcache = 4'h0; 
assign wvalid  = wvalid_dma | wvalid_ddr ;
assign wid     = wvalid_dma ? {4'h0, 4'h1} :  {4'h0, 4'h2};
assign wdata   = wvalid_dma ? wdata_dma :  wdata_ddr;
assign wstrb   = wvalid_dma ? wstrb_dma :  wstrb_ddr;
assign wlast   = wvalid_dma ? wlast_dma :  wlast_ddr;
assign bready  = 1'b1;

wire apb_valid_req;
reg  apb_psel;
reg  apb_penable;
reg  apb_rw;
wire [31:0]apb_addr;
wire [31:0]apb_wdata;
assign apb_valid_req = arvalid_dev || awvalid_dev ;
assign apb_addr = dma_dev_addr[31] ? (reg_ac97[32] ? {24'h1fe600, dma_dev_addr[15:8]} :{24'h1fe600, dma_dev_addr[7:0]}) : dma_dev_addr; 
assign apb_wdata= reg_ac97[32] ? reg_ac97[31:0] : wdata_tmp0;
always@(posedge clk)
begin
        if(~rst_n)begin
                apb_psel<= 1'b0;
                apb_penable <= 1'b0;
                apb_rw <= 1'b0;
        end
        else begin
                if(dma_gnt) begin
                        if(apb_penable)begin
                               apb_psel <= 1'b0;
                               apb_rw   <= 1'b0;
                               apb_penable <= 1'b0;
                        end else if(arvalid_dev | awvalid_dev) begin
                               apb_psel <= 1'b1;
                               apb_rw   <= awvalid_dev ;
                               apb_penable <= apb_psel;
                        end else
                               apb_penable <= apb_psel;
                 end else begin
                        apb_psel<= 1'b0;
                        apb_penable <= 1'b0;
                        apb_rw <= 1'b0;
                 end
        end
end

endmodule