`include "VX_platform.vh"

module VX_ipdom_stack #(
    parameter WIDTH = 1,
    parameter DEPTH = 1
) (
    input  wire               clk,
    input  wire               reset,
    input  wire [WIDTH - 1:0] q1,
    input  wire [WIDTH - 1:0] q2,
    output wire [WIDTH - 1:0] d,
    input  wire               push,
    input  wire               pop,
    output wire               empty,
    output wire               full
);
    localparam STACK_SIZE = 2 ** DEPTH;

    reg [WIDTH-1:0] stack_1 [0:STACK_SIZE-1];
    reg [WIDTH-1:0] stack_2 [0:STACK_SIZE-1];
    reg is_part [0:STACK_SIZE-1];
    
    reg [DEPTH-1:0] rd_ptr, wr_ptr;

    reg [WIDTH - 1:0] d1, d2;
    reg p;

    always @(posedge clk) begin
        if (reset) begin   
            rd_ptr <= 0;
            wr_ptr <= 0;
        end else begin
            if (push) begin
                rd_ptr <= wr_ptr;
                wr_ptr <= wr_ptr + DEPTH'(1);
            end else if (pop) begin            
                wr_ptr <= wr_ptr - DEPTH'(is_part[rd_ptr]);
                rd_ptr <= rd_ptr - DEPTH'(is_part[rd_ptr]);
            end
        end
    end

    always @(posedge clk) begin
        if (push) begin
            stack_1[wr_ptr] <= q1;  
        end
    end
    assign d1 = stack_1[rd_ptr];

    always @(posedge clk) begin
        if (push) begin
            stack_2[wr_ptr] <= q2;
        end
    end
    assign d2 = stack_2[rd_ptr];

    always @(posedge clk) begin
        if (push) begin
            is_part[wr_ptr] <= 0;   
        end else if (pop) begin            
            is_part[rd_ptr] <= 1;
        end
    end
    assign p = is_part[rd_ptr];

    assign d     = p ? d1 : d2;
    assign empty = ~(| wr_ptr);
    assign full  = ((STACK_SIZE-1) == wr_ptr);

endmodule