module pic10_core(input clock, reset, output [3:0] prog_adr, input [11:0] prog_data, input [3:0] gpi, output reg [7:0] gpo);
    wire [7:0] reg_rdata;
    reg [7:0] result;
    reg [7:0] w;
    reg [1:0] phase;
    reg [3:0] pc;
    reg [3:0] next_pc;
    reg skip, next_skip, next_skip_zero;
    reg reg_we, w_we;

    assign prog_adr = pc;

    always @(posedge clock, negedge reset)
    begin
        if (!reset) begin
            phase <= 2'b0;
        end else begin
            phase <= phase + 1'b1;
        end
    end

    always @(posedge clock, negedge reset)
    begin
        if (!reset) begin
            pc <= 1'b0;
            next_pc <= 1'b0;
            w <= 1'b0;
            next_skip <= 1'b0;
        end else begin
            if (phase == 0) begin
                skip <= next_skip;
                next_skip <= 1'b0;
                next_skip_zero <= 1'b0;
                reg_we <= 1'b0;
                w_we <= 1'b0;
                pc <= next_pc;
            end else if (phase == 1) begin
                next_pc <= prog_adr + 1'b1;
                if (prog_data[11:10] == 2'b00) begin
                    reg_we <= prog_data[5];
                    w_we <= ~prog_data[5];
                    case (prog_data[9:6])
                        4'b0000: result <= w;
                        4'b0001: result <= 0;
                        4'b0010: result <= reg_rdata - w;
                        4'b0011: result <= reg_rdata - 1;
                        4'b0100: result <= reg_rdata | w;
                        4'b0101: result <= reg_rdata & w;
                        4'b0110: result <= reg_rdata ^ w;
                        4'b0111: result <= reg_rdata + w;
                        4'b1000: result <= reg_rdata;
                        4'b1001: result <= ~reg_rdata;
                        4'b1010: result <= reg_rdata + 1;
                        4'b1011: begin result <= reg_rdata - 1; next_skip_zero <= 1'b1; end
                        4'b1111: begin result <= reg_rdata + 1; next_skip_zero <= 1'b1; end
                    endcase
                end else if (prog_data[11:10] == 2'b01) begin
                    reg_we <= 1'b1;
                    case (prog_data[9:8])
                        2'b00: result <= reg_rdata & ~(1 << prog_data[7:5]);
                        2'b01: result <= reg_rdata | (1 << prog_data[7:5]);
                        2'b10: begin result <= reg_rdata; next_skip <= ~reg_rdata[prog_data[7:5]]; end
                        2'b11: begin result <= reg_rdata; next_skip <= reg_rdata[prog_data[7:5]]; end
                    endcase
                end else if (prog_data[11:10] == 2'b10) begin
                    // no call, return
                    if (!skip)
                        next_pc <= prog_data[3:0];
                end else if (prog_data[11:10] == 2'b11) begin
                    w_we <= 1'b1;
                    case (prog_data[9:8])
                        2'b00: result <= prog_data[7:0];
                        2'b01: result <= prog_data[7:0] | w;
                        2'b10: result <= prog_data[7:0] & w;
                        2'b11: result <= prog_data[7:0] ^ w;
                    endcase
                end
            end else if (phase == 2) begin
                if (next_skip_zero) begin
                    next_skip <= (result == 0);
                end
                if (!skip) begin
                    if (w_we)
                        w <= result;
                end
            end else if (phase == 3) begin
                // ...
            end
        end
    end

    wire [2:0] reg_addr = prog_data[2:0];
    always @(posedge clock) begin
        if (reg_we && regf_we && (reg_addr == 7))
            gpo <= result;
    end

    wire [7:0] regf_data[0:7];
    assign regf_data[6] = {4'b0000, gpi};
    assign regf_data[7] = gpo;

    assign reg_rdata = regf_data[reg_addr];

    // register file
    wire regf_we = phase[1] & !skip;

    generate
        genvar ii, jj;
        for (ii = 0; ii < 6; ii = ii + 1'b1) begin:word
            wire word_we;
            sky130_fd_sc_hd__and3_1 word_we_i ( // make sure this is really glitch free
                .A(reg_addr[2:0] == ii),
                .B(regf_we),
                .C(reg_we),
                .X(word_we)
            );
            for (jj = 0; jj < 8; jj = jj + 1'b1) begin:bits
                sky130_fd_sc_hd__dlrtp_1 rfbit_i (
                    .GATE(word_we),
                    .RESET_B(reset),
                    .D(result[jj]),
                    .Q(regf_data[ii][jj])
                );
            end
        end
    endgenerate

endmodule