
`timescale 1ns/10ps

module MyAPBFabricMaster
(
   // AMBA Master Interface
        PCLK,
        SYSRESETN,
        PRESETN,
        PENABLE_M,
        PWRITE_M,
        PSEL_M,
        PADDR_M,
        PWDATA_M,
        PRDATA_M,
        PREADY_M,
        PSLVERR_M,
                
    // ACE trigger  
        ADC2_PPE_DONE,

    // SIGNAL REST OF FABRIC
        FPGA_TRIGGER,
        ENABLE_PWM 
);


// ---------------------------------------------------------------------
// GENERICS
// ---------------------------------------------------------------------

parameter APB_AWIDTH  =  32;
parameter APB_DWIDTH  =  32;

// ---------------------------------------------------------------------
// Port declarations
// ---------------------------------------------------------------------

input                       PCLK;
input                       SYSRESETN;
output                       PRESETN;
output                      PENABLE_M;
output                      PWRITE_M;
output                      PSEL_M;
output[APB_AWIDTH - 1:0]    PADDR_M;
output[APB_DWIDTH - 1:0]    PWDATA_M;
input [APB_DWIDTH - 1:0]    PRDATA_M;
input                       PREADY_M;
input                       PSLVERR_M;
input                       ADC2_PPE_DONE;
output                      FPGA_TRIGGER;
output                      ENABLE_PWM;
        
    
wire                        PRESETN;
reg                         PENABLE_M;
reg                         PWRITE_M;
reg                         PSEL_M;
reg   [APB_AWIDTH - 1:0]    PADDR_M;
reg   [APB_DWIDTH - 1:0]    PWDATA_M;
wire                        ADC2_PPE_DONE;
reg                         FPGA_TRIGGER;
reg                         ENABLE_PWM;

assign PRESETN = SYSRESETN;


// ---------------------------------------------------------------------
//  delay counter ( mimic the fabric logic doing some processing )
// ---------------------------------------------------------------------
reg [15:0] counter;
always @( posedge PCLK or negedge SYSRESETN )
begin
    if ( !SYSRESETN ) begin
        counter <= 0;
    end
    else begin
        if ( ENABLE_PWM ) begin
            counter <= counter + 1;
        end
        else begin
            counter <= 0;
        end
    end
end
assign counter_done = counter == 16'd256;

// ---------------------------------------------------------------------
//  Control
// ---------------------------------------------------------------------
reg [3:0] state;

parameter[3:0] IDLE             = 0;
parameter[3:0] DISABLE_TRIG1    = 1;
parameter[3:0] DISABLE_TRIG2    = 2;
parameter[3:0] ST_ENABLE_PWM    = 3;
parameter[3:0] WAIT_FABLOGIC    = 4;
parameter[3:0] WRITE_PC0_1      = 5;
parameter[3:0] WRITE_PC0_2      = 6;
parameter[3:0] WRITE_PC0_ENABLE1= 7;
parameter[3:0] WRITE_PC0_ENABLE2=8;

parameter[31:0] PPE_FLAGS0_IRQ_CLR_ADDR = 32'h4002122c;
parameter[31:0] PPE_FLAGS0_IRQ_CLR_WRITEDATA = 32'h00008000;


parameter[31:0] SSE_PC0_LO_ADDR = 32'h40020040;
parameter[31:0] SSE_PC0_LO_DATA = 32'h2;

parameter[31:0] SSE_PC0_CTRL_ADDR = 32'h40020048;
parameter[31:0] SSE_PC0_CTRL_DATA = 32'h1;


always @( posedge PCLK or negedge SYSRESETN )
begin
    if ( !SYSRESETN ) begin
        PADDR_M <= 0;
        PWDATA_M <= 0;
        PSEL_M <= 0;
        PWRITE_M <= 0; 
        ENABLE_PWM <= 0;
        PENABLE_M <= 1'b0;
        FPGA_TRIGGER <= 0;
        state <= IDLE;
    end
    else begin
        case ( state )

            IDLE:
              begin
                if ( ADC2_PPE_DONE ) begin
                    PADDR_M <= PPE_FLAGS0_IRQ_CLR_ADDR;
                    PWDATA_M <= PPE_FLAGS0_IRQ_CLR_WRITEDATA;
                    PSEL_M <= 1'b1;
                    PWRITE_M <= 1'b1;
                    
                    FPGA_TRIGGER <= 1;
                    state <= DISABLE_TRIG1;
                end                
              end

            // trigger received from ACE.  
            // means sequence has finished, disable the trigger flag so we
            // don't accidently get re-triggered
            DISABLE_TRIG1:
              begin                
                PENABLE_M <= 1'b1;
                state <= DISABLE_TRIG2;
              end

            DISABLE_TRIG2:
              begin
                if ( PREADY_M == 1'b1 )
                begin
                    PSEL_M <= 1'b0;
                    PWRITE_M <= 1'b0; 
                    PENABLE_M <= 1'b0;   
                    state <= ST_ENABLE_PWM;    
                end        
              end

            // fabric logic is proceeding
            // this could actually be occuring sooner, 
            // as soon as trigger was received
            ST_ENABLE_PWM:
              begin
                ENABLE_PWM <= 1'b1;
                
                PADDR_M <= SSE_PC0_LO_ADDR;
                PWDATA_M <= SSE_PC0_LO_DATA;
                PSEL_M <= 1'b1;
                PWRITE_M <= 1'b1;

                state <= WRITE_PC0_1;
              end
        

            // fabric completed, let's setup the ACE sequence again
            // write to the program counter w/ the beginning of the SSE loop
            WRITE_PC0_1:
              begin 
                PENABLE_M <= 1'b1;
                state <= WRITE_PC0_2;
              end

            WRITE_PC0_2:
              begin
                if ( PREADY_M == 1'b1 )
                begin
                 PENABLE_M <= 1'b0; 

                 PSEL_M <= 1'b1;
                 PWRITE_M <= 1'b1; 
                 PADDR_M <= SSE_PC0_CTRL_ADDR;
                 PWDATA_M <= SSE_PC0_CTRL_DATA;
                 state <= WRITE_PC0_ENABLE1;
                end
              end

            // enable the PCx enable bit
            WRITE_PC0_ENABLE1:
              begin
                PENABLE_M <= 1'b1;
                 state <= WRITE_PC0_ENABLE2;
              end

            WRITE_PC0_ENABLE2:
              begin
                if ( PREADY_M == 1'b1 )
                begin
                 PSEL_M <= 1'b0;
                 PWRITE_M <= 1'b0; 
                 PENABLE_M <= 1'b0; 
                 state <= WAIT_FABLOGIC;
                end
              end


            WAIT_FABLOGIC:
              begin
                 if ( counter_done ) begin
                     ENABLE_PWM <= 1'b0;
                     FPGA_TRIGGER <= 0;
                     state <= IDLE;
                 end
              end


        endcase
    end
end


endmodule