module sequential_multiplier #(
    parameter p_data_width = 4
)(
    output wire [(2*p_data_width-1):0] o_w_out,
    output wire [(p_data_width-1):0] o_w_disp_a,
    output wire [(p_data_width-1):0] o_w_disp_b,
    input wire [(p_data_width-1):0] i_w_a,
    input wire [(p_data_width-1):0] i_w_b,
    input wire i_w_clk,
    input wire i_w_reset,
    input wire i_w_write,
    input wire i_w_multiply,
    input wire i_w_display 
);

    wire l_w_a_we;
    wire l_w_a_oe;
    wire [(p_data_width-1):0] l_w_a_out;
    register #(.p_data_width(p_data_width)) l_m_register_0 (
        .o_w_out(l_w_a_out),
        .o_w_disp_out(o_w_disp_a),
        .i_w_clk(i_w_clk),
        .i_w_reset(i_w_reset),
        .i_w_in(i_w_a),
        .i_w_we(l_w_a_we),
        .i_w_oe(l_w_a_oe)
    );

    wire l_w_b_we;
    wire l_w_b_oe;
    wire [(p_data_width-1):0] l_w_b_out;
    register #(.p_data_width(p_data_width)) l_m_register_1 (
        .o_w_out(l_w_b_out),
        .o_w_disp_out(o_w_disp_b),
        .i_w_clk(i_w_clk),
        .i_w_reset(i_w_reset),
        .i_w_in(i_w_b),
        .i_w_we(l_w_b_we),
        .i_w_oe(l_w_b_oe)
    );
    

    wire l_w_c_we;
    wire l_w_c_oe;
    wire [(2*p_data_width-1):0] l_w_c_out;
    wire [(2*p_data_width-1):0] l_w_c_in;
    assign l_w_c_in = (l_w_a_out * l_w_b_out);
    register #(.p_data_width(2*p_data_width)) l_m_register_2 (
        .o_w_out(l_w_c_out),
        .i_w_clk(i_w_clk),
        .i_w_reset(i_w_reset),
        .i_w_in(l_w_c_in),
        .i_w_we(l_w_c_we),
        .i_w_oe(l_w_c_oe)
    );

    localparam STATE_INITIAL = 2'd0;
    localparam STATE_WRITE = 2'd1;
    localparam STATE_MULTIPLY = 2'd2;
    localparam STATE_DISPLAY = 2'd3;

    reg [1:0] l_r_state;
    reg [1:0] l_r_next_state;

    always @(posedge i_w_clk) begin
		if(i_w_reset == 1'b0) begin
            l_r_state <= STATE_INITIAL;
        end else begin
            l_r_state <= l_r_next_state;
        end
	end

    always @(*) begin 
        l_r_next_state = i_w_write ?
                            STATE_WRITE :
                            (i_w_multiply ?
                                STATE_MULTIPLY :
                                (i_w_display ?
                                    STATE_DISPLAY :
                                    STATE_INITIAL));
    end

    assign l_w_a_we = l_r_state == STATE_WRITE;
    assign l_w_a_oe = l_r_state == STATE_MULTIPLY;
    assign l_w_b_we = l_r_state == STATE_WRITE;
    assign l_w_b_oe = l_r_state == STATE_MULTIPLY;
    assign l_w_c_we = l_r_state == STATE_MULTIPLY;
    assign l_w_c_oe = l_r_state == STATE_DISPLAY;

    assign o_w_out = l_w_c_out;

endmodule