// APB_MEM_CTRL.v
module APB_MEM_CTRL( 
//APB Side
input PRESETn,  PCLK, PREADY, PSLVERR,
input [31:0] PRDATA,
output reg PENABLE, PSEL, PWRITE,
output reg [23:0] PADDR,
output reg [31:0] PWDATA,
//Backend Signals
//input [31:0] start_address,
output reg busy,
output reg dac_out_enable,
output  reg [3:0] cur_state );

reg[3:0] current_state;
reg [31:0] Adc0_poll_Reg;
reg [15:0] Adc0_Shift_Reg;

// ACE Poll Address is from 40021000
// DAC Address is from 40020500
parameter AD0POLL_DATA_OFFSET   = 24'h001000;
// This has [31:16] - Reserved; 15 - Calibrate, 14 - Sample,
// 13 - Busy, 12- Data Valid, [11:0] - ADC Result
parameter DAC_DATA_OFFSET       = 24'h000500; 


parameter [3:0] IDLE = 4'b0000, 
FIC_UPPER_ACCESS_0  = 4'b0001, 
FIC_UPPER_ACCESS_1  = 4'b0010, 
FIC_UPPER_ACCESS_2  = 4'b0011,
FIC_READPOLL_0      = 4'b0100, 
FIC_READPOLL_1      = 4'b0101, 
FIC_READPOLL_2      = 4'b0110, 
FIC_WRITE_0         = 4'b0111, 
FIC_WRITE_1         = 4'b1000, 
FIC_WRITE_2         = 4'b1001;

reg[31:00] delay_start;

//always @(posedge PCLK, negedge PRESETn)
//begin
//  if ( PRESETn == 1'b0 )
//    delay_start <= 0;
//  else
//    delay_start <= delay_start + 1;
//end

always@(posedge PCLK, negedge PRESETn)
    begin

    if(PRESETn == 1'b0)
    begin
        PADDR           <=  24'h000000;
        PWDATA          <=  24'h000000;
        PENABLE         <=  1'b0;
        PSEL            <=  1'b0;
        PWRITE          <=  1'b0;
        busy            <=  1'b0;
        dac_out_enable  <=  1'b0;
        cur_state       <=  4'b0000;
        current_state   <=  IDLE;
        delay_start <= 0;
    end

    else 
    begin
    
    case(current_state) /* synthesis parallel_case */ 
    
    IDLE:
    begin
        
        cur_state       <=  4'b0000;
        dac_out_enable  <=  1'b0;
        busy            <=  1'b0;
        PENABLE         <=  1'b0;
        PSEL            <=  1'b0;
        PWRITE          <=  1'b0;
        if ( delay_start < 32'd16384 )
            begin
                current_state   <=  IDLE;
                delay_start <= delay_start + 1;
            end
        else
            begin
                current_state   <=  FIC_UPPER_ACCESS_0;
                delay_start <= 0;
            end
    end

    FIC_UPPER_ACCESS_0://Write To IADDR  Indirect Address(We want to access 0x40021000)
    begin
        cur_state       <=  4'b0001;
        busy            <=  1'b1;
        PSEL            <=  1'b1;
        PWRITE          <=  1'b1;
        PWDATA          <=  32'h40020000;
        PADDR           <=  24'h010000; // This is for 64K access setting IADDR
        current_state   <=  FIC_UPPER_ACCESS_1;
    end
    
    FIC_UPPER_ACCESS_1: //WRITE ADDRESS PHASE
    begin
        cur_state       <=  4'b0010;
        PENABLE         <=  1'b1;
        current_state   <=  FIC_UPPER_ACCESS_2;
    end

    FIC_UPPER_ACCESS_2: //WRITE DATA PHASE
    begin
        if(PREADY == 1'b1)
        begin
        PSEL            <=  1'b0;
        PENABLE         <=  1'b0;
        current_state   <=  FIC_READPOLL_0;
        end
        else
        begin
        current_state   <=  FIC_UPPER_ACCESS_2;
        end
        cur_state       <=  4'b0011;
 
    end

    FIC_READPOLL_0: // READ ADDRESS PHASE 
    begin
        busy            <=  1'b1;
        PSEL            <=  1'b1;
        PWRITE          <=  1'b0;
        PADDR           <=  AD0POLL_DATA_OFFSET;
        PWDATA          <=  32'h00000000;
        current_state   <=  FIC_READPOLL_1;
        cur_state       <=  4'b0100;
        dac_out_enable  <=  1'b0;
    end

    FIC_READPOLL_1: // READ DATA PHASE 
    begin
        PENABLE         <=  1'b1;
        current_state   <=  FIC_READPOLL_2;
        cur_state       <=  4'b0101;
    end


    FIC_READPOLL_2: // READ DATA PHASE 
    begin
        if(PREADY == 1'b1)
            begin
            PSEL            <=  1'b0;
            PENABLE         <=  1'b0;
            busy            <=  1'b1;
            Adc0_poll_Reg <=  PRDATA;
                if((PRDATA[12] == 1'b1) & (PRDATA[13] == 1'b0))
                     begin
                        current_state   <=  FIC_WRITE_0;
                     end
                else
                     begin
                        current_state   <=  FIC_READPOLL_0;
                     end
            end
         else
            begin
            current_state   <=  FIC_READPOLL_2;
            end

         cur_state       <=  4'b0110;

    end

    
    FIC_WRITE_0: // READ ADDRESS PHASE 
    begin
        busy            <=  1'b1;
        PSEL            <=  1'b1;
        PWRITE          <=  1'b1;
        PADDR           <=  DAC_DATA_OFFSET;
        PWDATA[15:4]    <=  Adc0_poll_Reg[11:0];
        current_state   <=  FIC_WRITE_1;
        cur_state       <=  4'b0111;
        dac_out_enable  <=  1'b1;

    end

    FIC_WRITE_1: // READ DATA PHASE 
    begin
        PENABLE         <=  1'b1;
        current_state   <=  FIC_WRITE_2;
        cur_state       <=  4'b1000;
    end


    FIC_WRITE_2: // READ DATA PHASE 
    begin
        if(PREADY == 1'b1)
            begin
            PSEL            <=  1'b0;
            PENABLE         <=  1'b0;
            busy            <=  1'b1;
            PWDATA          <=  32'h00000000;
                if ( delay_start < 32'd32 )
                    begin
                        current_state   <=  FIC_WRITE_2;
                        delay_start <= delay_start + 1;
                    end
                else
                    begin
                        current_state   <=  FIC_READPOLL_0;
                        delay_start <= 0;
                    end
            end        
         else
            begin
            current_state   <=  FIC_WRITE_2;
            end

         cur_state       <=  4'b1001;

    end

    default:
        begin
            current_state   <=  IDLE;
        end

    endcase

 end //if 

end // always

endmodule