module exploit
#(
    parameter DELAY_FRAMES = 234 // 27,000,000 (27Mhz) / 115200 Baud rate
)
(
    // exploit
    input clk_in,
    output power_tx,
    output [5:0] led,

    // uart
    input clk,
    input btn1,
    input uart_rx,
    output uart_tx
);

////////// EXPLOIT
localparam INSTRUCTION_OFFSET = 100;

// da official exploit code
localparam EXPLOIT_BYTES = {8'h5D,8'h5D,8'h5D,8'h5D};


//// glitch logic

localparam EXPLOIT_BYTES_LEN = $bits(EXPLOIT_BYTES)-1; // $bits() seems to work // https://www.linkedin.com/pulse/bits-clog2-size-uses-differences-muhammed-kawser-ahmed
localparam LEDS_ON = 0;
localparam LEDS_OFF = 6'b111111;

reg [1:0] power_tx_reg = 1;
reg [1:0] led_run = 1;
reg [1:0] rst = 0;
reg [1:0] running = 1; 
reg [5:0] ledCounter = 0;
reg [23:0] instruction_counter = 0;
reg [23:0] exploit_tx_count = 0;
reg [EXPLOIT_BYTES_LEN:0] exploit_bytes_reg = EXPLOIT_BYTES; 

always @(posedge clk_in) begin
    if(rst == 1) begin
        running = 1;
        power_tx_reg = 1;
        rst = 0;
    end

    if(instruction_counter == INSTRUCTION_OFFSET) begin
        power_tx_reg = 0;
        rst = 1;
    end

    if(running == 1) begin
        if(instruction_counter >= INSTRUCTION_OFFSET && instruction_counter <= INSTRUCTION_OFFSET+EXPLOIT_BYTES_LEN) begin 
            led_run <= 1;
        end else begin
            led_run <= 0;
        end

        if(led_run == 1) begin
           ledCounter <= ledCounter + 1;
           if(ledCounter == LEDS_OFF) begin
                ledCounter <= LEDS_ON;
           end
        end

        if(instruction_counter == INSTRUCTION_OFFSET+EXPLOIT_BYTES_LEN) begin
            ledCounter <= LEDS_ON;
            rst = 1;
            running = 0;
        end

        instruction_counter <= instruction_counter + 1;
    end
end


//// uart rx
// uart shit ganked from https://raw.githubusercontent.com/lushaylabs/tangnano9k-series-examples/
// of https://learn.lushaylabs.com

localparam HALF_DELAY_WAIT = (DELAY_FRAMES / 2);

reg [3:0] rxState = 0;
reg [12:0] rxCounter = 0;
reg [7:0] dataIn = 0;
reg [2:0] rxBitNumber = 0;
reg byteReady = 0;

localparam RX_STATE_IDLE = 0;
localparam RX_STATE_START_BIT = 1;
localparam RX_STATE_READ_WAIT = 2;
localparam RX_STATE_READ = 3;
localparam RX_STATE_STOP_BIT = 5;

always @(posedge clk) begin
    case (rxState)
        RX_STATE_IDLE: begin
            if (uart_rx == 0) begin
                rxState <= RX_STATE_START_BIT;
                rxCounter <= 1;
                rxBitNumber <= 0;
                byteReady <= 0;
            end
        end 
        RX_STATE_START_BIT: begin
            if (rxCounter == HALF_DELAY_WAIT) begin
                rxState <= RX_STATE_READ_WAIT;
                rxCounter <= 1;
            end else 
                rxCounter <= rxCounter + 1;
        end
        RX_STATE_READ_WAIT: begin
            rxCounter <= rxCounter + 1;
            if ((rxCounter + 1) == DELAY_FRAMES) begin
                rxState <= RX_STATE_READ;
            end
        end
        RX_STATE_READ: begin
            rxCounter <= 1;
            dataIn <= {uart_rx, dataIn[7:1]};
            rxBitNumber <= rxBitNumber + 1;
            if (rxBitNumber == 3'b111)
                rxState <= RX_STATE_STOP_BIT;
            else
                rxState <= RX_STATE_READ_WAIT;
        end
        RX_STATE_STOP_BIT: begin
            rxCounter <= rxCounter + 1;
            if ((rxCounter + 1) == DELAY_FRAMES) begin
                rxState <= RX_STATE_IDLE;
                rxCounter <= 0;
                byteReady <= 1;
            end
        end
    endcase
end


//// uart tx

reg [3:0] txState = 0;
reg [24:0] txCounter = 0;
reg [1:0] txPinRegister = 1;
reg [2:0] txBitNumber = 0;
reg [3:0] txByteCounter = 0;

localparam MEMORY_LENGTH = 5;

localparam TX_STATE_IDLE = 0;
localparam TX_STATE_START_BIT = 1;
localparam TX_STATE_WRITE = 2;
localparam TX_STATE_STOP_BIT = 3;
localparam TX_STATE_DEBOUNCE = 4;

always @(posedge clk) begin
    case (txState)
        TX_STATE_IDLE: begin
            if (btn1 == 0) begin
                txState <= TX_STATE_START_BIT;
                txCounter <= 0;
                txByteCounter <= 0;
            end
            else begin
                txPinRegister <= 1;
            end
        end 
        TX_STATE_START_BIT: begin
            txPinRegister <= 0;
            if ((txCounter + 1) == DELAY_FRAMES) begin
                txState <= TX_STATE_WRITE;
                txBitNumber <= 0;
                txCounter <= 0;
            end else 
                txCounter <= txCounter + 1;
        end
        TX_STATE_WRITE: begin
            txPinRegister <= exploit_bytes_reg[txBitNumber];
            if ((txCounter + 1) == DELAY_FRAMES) begin
                if (txBitNumber == 7) begin
                    txState <= TX_STATE_STOP_BIT;
                end else begin
                    txState <= TX_STATE_WRITE;
                    txBitNumber <= txBitNumber + 1;
                end
                txCounter <= 0;
            end else 
                txCounter <= txCounter + 1;
        end
        TX_STATE_STOP_BIT: begin
            txPinRegister <= 1;
            if ((txCounter + 1) == DELAY_FRAMES) begin
                if (txByteCounter == MEMORY_LENGTH - 1) begin
                    txState <= TX_STATE_DEBOUNCE;
                end else begin
                    txByteCounter <= txByteCounter + 1;
                    txState <= TX_STATE_START_BIT;
                end
                txCounter <= 0;
            end else 
                txCounter <= txCounter + 1;
        end
        TX_STATE_DEBOUNCE: begin
            if (txCounter == 23'b111111111111111111) begin
                if (btn1 == 1) 
                    txState <= TX_STATE_IDLE;
            end else
                txCounter <= txCounter + 1;
        end
    endcase      
end

// assigns to output 
assign led = ledCounter;
assign power_tx = power_tx_reg;
assign uart_tx = txPinRegister;

endmodule