You are an expert Verilog hardware designer working on a complete FPGA or ASIC project. You are given the full source code of a Verilog project. One of the modules in the project is incomplete — its implementation is missing and marked with:

// >>> Module Implementation Begin

// <<< Module Implementation End

Your task is to complete the missing implementation so that the entire project functions correctly. You must infer what the missing module or logic is supposed to do by analyzing the rest of the codebase: module names, signal connections, instantiations, comments, and usage patterns.

Follow these rules:

1. Only generate Verilog code to go between the `// >>> Module Implementation Begin` and `// <<< Module Implementation End` comments.
2. Use Verilog-2001 syntax. Ensure the code is synthesizable.
3. Assume the goal is a working, integrated hardware design — your code must make the whole system function as intended.
4. Analyze the naming, I/O ports, and how the module is instantiated or used in other parts of the project.
5. Implement correct behavior based on design context. Do not guess randomly — reason it out.
6. Avoid vendor-specific features unless explicitly required.
7. Do not output comments, explanation, or anything outside the required code region unless explicitly asked.

Your output should contain **only the Verilog code** that fits inside the marked region.

module keccak_alu (
    input [64*5-1:0] registers,
    input [1:0] mode,
    output reg [63:0] keccak_output
);

  function [63:0] ROL(input [63:0] a, input [63:0] offset);
    begin
      ROL = (a << offset) ^ (a >> (64 - offset));
    end
  endfunction

  always @* begin
    case (mode)
      2'b00: begin  // kxorinvand
        keccak_output = registers[0*64+:64] ^ ((~registers[1*64+:64]) & registers[2*64+:64]);
      end
      2'b01: begin  // ktheta
        keccak_output = registers[0*64+:64] ^ registers[1*64+:64] ^ registers[2*64+:64] ^ registers[3*64+:64];
      end
      2'b10: begin  // krol
        keccak_output = registers[0*64+:64] ^ ROL(registers[1*64+:64], registers[2*64+:64]);
      end
      2'b11: begin  // kxor
        keccak_output = registers[0*64+:64] ^ registers[1*64+:64];
      end
    endcase
  end
endmodule


`default_nettype none

module tt_um_zoom_zoom (
    input  wire [7:0] ui_in,    // Dedicated inputs
    output wire [7:0] uo_out,   // Dedicated outputs
    input  wire [7:0] uio_in,   // IOs: Input path
    output wire [7:0] uio_out,  // IOs: Output path
    output wire [7:0] uio_oe,   // IOs: Enable path (active high: 0=input, 1=output)
    input  wire       ena,      // always 1 when the design is powered, so you can ignore it
    input  wire       clk,      // clock
    input  wire       rst_n     // reset - low to reset
);

  wire [7:0] data_output_pins;  
  wire [15:0] memory_in;
  wire [7:0] iovalue;
  wire memory_ready;
  wire write_complete;
  wire uart_inbound;
  wire set_rx_speed;
  wire [12:0] rx_speed;
  wire [15:0] request_address;
  wire request_type;
  wire request;
  wire [15:0] data_out;
  wire [7:0] data_input_pins;
//   wire [15:0] memory_write;
  wire write_enable, register_enable, read_enable, lower_bit, upper_bit, tx;  
  wire [7:0] data_received;  // Output from uart_rx

  // input
  wire lower_byte_in = ui_in[0];
  wire upper_byte_in = ui_in[1];
  wire rx = ui_in[2];  // UART RX input
  wire IN3 = ui_in[3];
  wire IN4 = ui_in[4];
  wire IN5 = ui_in[5];
  wire IN6 = ui_in[6];
  wire IN7 = ui_in[7];

  // output
  assign uo_out[0] = write_enable;
  assign uo_out[1] = register_enable;
  assign uo_out[2] = read_enable;
  assign uo_out[3] = lower_bit;
  assign uo_out[4] = tx;
  assign uo_out[5] = upper_bit;
  assign uo_out[6] = 0;  // unused
  assign uo_out[7] = 0;  // unused

  // input output
  assign uio_out = data_output_pins;   
  assign data_input_pins = uio_in;     
  assign uio_oe = iovalue;             

  x3q16 cpu (
      .clk(clk),
      .reset(~rst_n),  // Assuming active-low reset is converted to active-high for submodule
      .memory_in(memory_in),
      .memory_ready(memory_ready),
      .write_complete(write_complete),
      .uart_inbound(uart_inbound),
      .request_address(request_address),
      .request_type(request_type),
      .request(request),
      .data_out(data_out),
      .tx(tx),
      .set_rx_speed(set_rx_speed),
      .rx_speed(rx_speed)
  );

  memory_controller_arduino memory_controller (
      .clk(clk),
      .reset(~rst_n),  // Assuming active-low reset is converted to active-high for submodule
      .request_address(request_address),
      .request_type(request_type),
      .request(request),
      .memory_write(data_out),
      .data_out(memory_in),
      .memory_ready(memory_ready),
      .write_complete(write_complete),
      .write_enable(write_enable),  
      .register_enable(register_enable),
      .read_enable(read_enable),
      .lower_bit(lower_bit),
      .upper_bit(upper_bit),
      .lower_byte_in(lower_byte_in),
      .upper_byte_in(upper_byte_in),
      .data_input_pins(data_input_pins),
      .data_output_pins(data_output_pins),  // Connect data_output_pins properly
      .iovalue(iovalue),  
      .uart_inbound(uart_inbound),
      .data_received(data_received)
  );

  uart_rx uart_receiver (
      .clk(clk),
      .reset(~rst_n),  // Assuming active-low reset is converted to active-high for submodule
      .rx(rx),                          // RX input from ui_in
      .speed(rx_speed),                 // Default speed, or you can use another input if needed
      .set_speed(set_rx_speed),                 // No speed setting input; default to 0
      .uart_inbound(uart_inbound),      // Output to memory_controller
      .data_received(data_received)     // Output to memory_controller
  );

  // unused pins
  wire _unused = &{ena, IN3, IN4, IN5, IN6, IN7, 1'b0};

endmodule


// BHE, BLE, and CS Always set to High
module ram_16bit (
    input wire clk,              
    input wire we,   // write enable
    input wire oe,   // read enable
    input wire [15:0] addr, // bus 
    inout wire [15:0] data  // io pin 
);

    reg [15:0] memory [15:0];
    reg [15:0] dout;

    wire data_enable = !we && oe; 

    assign data = data_enable ? dout : 16'bz;

    always @(posedge clk) begin
        if (we) begin
            memory[addr] <= data; // write data to memory
        end 
        
        else if (oe) begin
            dout <= memory[addr]; // read data from memory
        end
    end
endmodule




module x3q16 (
		input clk,
		input reset,

		input [15:0] memory_in,
		input memory_ready,
		input write_complete,

		input uart_inbound,

		output reg [15:0] request_address,
		output reg request_type,  //0 is read, 1 is writes data_out to address
		output reg request,
		output reg [15:0] data_out,

		output wire tx,
		output wire set_rx_speed,
		output wire [12:0] rx_speed
	);
// >>> Module Implementation Begin

// <<< Module Implementation End
endmodule




module x3q16alu (
		input [15:0] a,
		input [15:0] b,
		input [2:0] mode,
		
		output reg [15:0] result,
		output reg equal_flag,
		output reg greater_a_flag
	);
	wire [15:0] sum;
	wire [15:0] sub;
	wire [8:0] mult;
	wire [7:0] mult_a, mult_b;
	
	assign sum = a + b;
	assign sub = a + ~b + 16'h0001;
	assign mult_a = a[7:0];
	assign mult_b = b[7:0];
	assign mult = mult_a * mult_b;
	
	always @(*) begin
		case (mode)
			3'b000: result = sum;
			3'b001: result = sub;
			3'b010: result = {7'b0, mult};
			3'b011: result = ~(a & b);
			3'b100: result = a << 1;
			3'b101: result = a >> 1;
			default: result = 16'h0000;
		endcase

		equal_flag = sub == 16'h0000;
		greater_a_flag = (~(sub == 16'h0000)) & ((b[15] & ~a[15]) | (a[15] & b[15] & ~sub[15]) | (~a[15] & ~b[15] & ~sub[15]));
	end
endmodule


module uart_tx (
        input clk,
        input reset,
        input [12:0] data,
        input send,
        input set,
        output reg busy,
        output reg tx_reg
    );

    localparam UART_SPEED_DEFAULT = 13'b1100001101010;

    reg [12:0] cycles_per_bit, cycle_counter;
    reg [7:0] data_sending;
    reg [2:0] bit_counter;
    reg [1:0] stage;
    //reg tx_reg;
    //assign tx = tx_reg;

    always @(posedge clk or posedge reset)
    begin
        if (reset) begin
            busy <= 1'b0;
            data_sending <= 8'h0;
            bit_counter <= 3'b0;
            tx_reg <= 1'b1;
            cycles_per_bit <= UART_SPEED_DEFAULT;
            cycle_counter <= 16'h0;
            stage <= 2'b00;
        end else if (set) begin
            cycles_per_bit <= data;
        end else begin
            case (stage)
                2'b00: begin
                    if (send) begin
                        tx_reg <= 1'b0;
                        cycle_counter <= 16'h0000;
                        stage <= 2'b01;
                        data_sending <= data[7:0];
                        busy <= 1'b1;
                    end
                end
                2'b01: begin
                    if (cycle_counter == cycles_per_bit) begin
                        cycle_counter <= 16'h0000;
                        tx_reg <= data_sending[bit_counter];
                        if (bit_counter == 3'b111) begin
                            stage <= 2'b10;
                        end else begin
                            bit_counter <= bit_counter + 3'b001;
                        end    
                    end else cycle_counter <= cycle_counter + 16'h0001;
                end
                2'b10: begin
                    if (cycle_counter == cycles_per_bit) begin
                        bit_counter <= 3'b000;
                        tx_reg <= 1'b1;
                        cycle_counter <= 16'h0000;
                        if (bit_counter == 3'b000) begin
                            busy <= 1'b0;
                            stage <= 2'b00;
                        end
                    end else cycle_counter <= cycle_counter + 16'h0001;
                end
            endcase
        end
    end
endmodule


(* keep_hierarchy *)
module uart_rx (
		input wire clk,
		input wire reset,
		input wire rx,
		input wire [12:0] speed,
		input wire set_speed,
		output reg uart_inbound,
		output reg [7:0] data_received
	);

	localparam UART_SPEED_DEFAULT = 13'h1869;

	reg [12:0] cycles_per_bit, cycle_counter;

	reg [7:0] data;
	reg [1:0] stage;
	reg [2:0] bit_counter;
	
	always @(posedge clk or posedge reset)
	begin
		if (reset) begin
			cycles_per_bit <= UART_SPEED_DEFAULT;
			cycle_counter <= 13'h0;
			data <= 8'h00;
			uart_inbound <= 1'b0;
			data_received <= 8'b0;
			stage <= 2'b0;
			bit_counter <= 3'b0;
		end else if (set_speed) begin
			cycles_per_bit <= speed;
		end else begin
			case (stage)
				2'b00: begin
					if (~rx) begin
						data <= 8'b0;
						bit_counter <= 3'b0;
						stage <= 2'b01;
						cycle_counter <= (cycles_per_bit != 13'b0) ? ((13'b1111111111110 - cycles_per_bit) + 13'h0002) : 13'b0;
					end
					uart_inbound <= 1'b0;
					data_received <= 8'b0;
				end
				2'b01: begin
					if (cycle_counter == cycles_per_bit) begin
						cycle_counter <= 13'b0;
						data[bit_counter] <= rx;
						if (bit_counter == 3'b111) begin
							stage <= 2'b10; 
						end else bit_counter <= bit_counter + 3'b001;
					end else cycle_counter <= cycle_counter + 13'b0000000000001;
				end
				2'b10: begin
					if (cycle_counter == cycles_per_bit) begin
						uart_inbound <= 1'b1;
						data_received <= data;
						stage <= 2'b00;
					end else cycle_counter <= cycle_counter + 13'b0000000000001;
				end
			endcase
		end
	end
endmodule


module memory_controller_arduino (
    input clk,
    input reset,

    // Interface with x3q16
    input [15:0] request_address,
    input request_type, // 0 for read, 1 for write
    input request,
    input [15:0] memory_write, 
    output reg [15:0] data_out, 
    output reg memory_ready,
    output reg write_complete,

    // Arduino output
    output reg write_enable,
    output reg register_enable,
    output reg read_enable,
    output reg lower_bit,
    output reg upper_bit,

    // Arduino input
    input lower_byte_in,
    input upper_byte_in,

    input [7:0] data_input_pins, 
    output reg [7:0] data_output_pins,

    // Updated iovalue signal
    output reg [7:0] iovalue,  // 8-bit: controls direction for each uio pin (0: input, 1: output)

    // UART Receiver Instantiation
    input wire uart_inbound,
    input wire [7:0] data_received  // Changed from single bit to 8 bits for data input
);

    parameter IDLE = 5'b00000;
    parameter WRITE_SETUP = 5'b00001;
    parameter WRITE_WAIT_1 = 5'b00010;
    parameter WRITE_ADDRESS_UPPER = 5'b00011;
    parameter WRITE_WAIT_2 = 5'b00100;
    parameter LOAD_DATA_LOWER = 5'b00101;
    parameter WRITE_WAIT_3 = 5'b00110;
    parameter LOAD_DATA_UPPER = 5'b00111;
    parameter WRITE_WAIT_4 = 5'b01000;
    parameter WRITE_COMPLETE = 5'b01001;
    parameter READ_SETUP = 5'b01010;
    parameter READ_WAIT_1 = 5'b01011;
    parameter READ_ADDRESS_UPPER = 5'b01100;
    parameter READ_WAIT_2 = 5'b01101;
    parameter READ_WAIT_FOR_LOWER_BYTE = 5'b01110;
    parameter READ_LOWER_BYTE = 5'b01111;
    parameter READ_WAIT_FOR_UPPER_BYTE = 5'b10000;
    parameter READ_UPPER_BYTE = 5'b10001;
    parameter READ_COMPLETE = 5'b10010;
    parameter UART_RECEIVE_ADDRESS = 5'b10011;
    parameter UART_WAIT_LOWER_BYTE = 5'b10101;
    parameter UART_RECEIVE_ADDRESS_UPPER = 5'b10110;
    parameter UART_WAIT_UPPER_BYTE = 5'b10111;
    parameter UART_RECEIVE_DATA = 5'b11000;
    parameter UART_WAIT_DATA_WRITE = 5'b11001;

    reg [4:0] state, next_state;

    reg [7:0] data_bus; 
    reg [5:0] wait_counter; 
    parameter WAIT_CYCLES = 6'd4; 

    reg uart_waiting;  
    reg [15:0] uart_memory_address;  

    always @(posedge clk or posedge reset) begin
        if (reset) begin
            state <= IDLE;
            memory_ready <= 1'b0;
            write_complete <= 1'b0;
            write_enable <= 1'b0;
            read_enable <= 1'b0;
            register_enable <= 1'b0;
            lower_bit <= 1'b0;
            upper_bit <= 1'b0;
            data_bus <= 8'b0;
            data_out <= 16'b0;
            wait_counter <= 6'b0;
            data_output_pins <= 8'b0; 
            iovalue <= 8'b0; // Default all to input
            uart_waiting <= 1'b0;
            uart_memory_address <= 16'b0;  // Initialize the UART memory address
        end else begin
            state <= next_state;

            // Manage wait counter
            if (state == WRITE_WAIT_1 || state == WRITE_WAIT_2 || state == WRITE_WAIT_3 || state == WRITE_WAIT_4 ||
                state == READ_WAIT_1 || state == READ_WAIT_2 || state == UART_WAIT_LOWER_BYTE || state == UART_WAIT_UPPER_BYTE || state == UART_WAIT_DATA_WRITE) begin
                wait_counter <= wait_counter + 1;
            end else begin
                wait_counter <= 6'b0;
            end

            case (state)
                IDLE: begin
                    memory_ready <= 1'b0;
                    write_complete <= 1'b0;
                    write_enable <= 1'b0;
                    read_enable <= 1'b0;
                    register_enable <= 1'b0;
                    lower_bit <= 1'b0;
                    upper_bit <= 1'b0;
                    data_bus <= 8'b0;
                    data_out <= 16'b0;
                    data_output_pins <= 8'b0;
                    iovalue <= 8'b0;  // Set all uio pins to input mode

                    if (uart_inbound) begin
                        uart_waiting <= 1'b1;
                        uart_memory_address <= 16'b111111110100000;
                        next_state <= UART_RECEIVE_ADDRESS;
                    end else if (request) begin  // Activate when request is 1
                        if (request_type == 1'b1) begin
                            next_state <= WRITE_SETUP;
                        end else if (request_type == 1'b0) begin
                            next_state <= READ_SETUP;
                        end
                    end else begin
                        next_state <= IDLE;
                    end
                end

                // Write Operation
                WRITE_SETUP: begin
                    write_enable <= 1'b1;
                    register_enable <= 1'b1;
                    lower_bit <= 1'b1;
                    data_output_pins <= request_address[7:0]; 
                    iovalue <= 8'b11111111;  // Set all uio pins to output mode
                    next_state <= WRITE_WAIT_1;
                end

                WRITE_WAIT_1: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= WRITE_ADDRESS_UPPER;
                    end else begin
                        next_state <= WRITE_WAIT_1;
                    end
                end

                WRITE_ADDRESS_UPPER: begin
                    lower_bit <= 1'b0;
                    upper_bit <= 1'b1;
                    data_output_pins <= request_address[15:8]; 
                    next_state <= WRITE_WAIT_2;
                end

                WRITE_WAIT_2: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= LOAD_DATA_LOWER;
                    end else begin
                        next_state <= WRITE_WAIT_2;
                    end
                end

                LOAD_DATA_LOWER: begin
                    register_enable <= 1'b0;
                    lower_bit <= 1'b1;
                    upper_bit <= 1'b0;
                    data_output_pins <= memory_write[7:0]; 
                    next_state <= WRITE_WAIT_3;
                end

                WRITE_WAIT_3: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= LOAD_DATA_UPPER;
                    end else begin
                        next_state <= WRITE_WAIT_3;
                    end
                end

                LOAD_DATA_UPPER: begin
                    lower_bit <= 1'b0;
                    upper_bit <= 1'b1;
                    data_output_pins <= memory_write[15:8]; 
                    next_state <= WRITE_WAIT_4;
                end

                WRITE_WAIT_4: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= WRITE_COMPLETE;
                    end else begin
                        next_state <= WRITE_WAIT_4;
                    end
                end

                WRITE_COMPLETE: begin
                    write_enable <= 1'b0;
                    upper_bit <= 1'b0;
                    write_complete <= 1'b1;
                    iovalue <= 8'b0;  
                    next_state <= IDLE;
                end

                // Read Operation
                READ_SETUP: begin
                    iovalue <= 8'b11111111;
                    read_enable <= 1'b1;
                    register_enable <= 1'b1;
                    lower_bit <= 1'b1;
                    data_output_pins <= request_address[7:0]; 
                    next_state <= READ_WAIT_1;
                end

                READ_WAIT_1: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= READ_ADDRESS_UPPER;
                    end else begin
                        next_state <= READ_WAIT_1;
                    end
                end

                READ_ADDRESS_UPPER: begin
                    lower_bit <= 1'b0;
                    upper_bit <= 1'b1;
                    data_output_pins <= request_address[15:8]; 
                    next_state <= READ_WAIT_2;
                end

                READ_WAIT_2: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= READ_WAIT_FOR_LOWER_BYTE;
                    end else begin
                        next_state <= READ_WAIT_2;
                    end
                end

                READ_WAIT_FOR_LOWER_BYTE: begin
                    register_enable <= 1'b0;
                    iovalue <= 8'b00000000;  
                    if (lower_byte_in) begin
                        data_out[7:0] <= data_input_pins;
                        next_state <= READ_LOWER_BYTE;
                    end else begin
                        next_state <= READ_WAIT_FOR_LOWER_BYTE;
                    end
                end

                READ_LOWER_BYTE: begin
                    data_out[7:0] <= data_input_pins;
                    next_state <= READ_WAIT_FOR_UPPER_BYTE;
                end

                READ_WAIT_FOR_UPPER_BYTE: begin
                    if (upper_byte_in) begin
                        next_state <= READ_UPPER_BYTE;
                    end else begin
                        next_state <= READ_WAIT_FOR_UPPER_BYTE;
                    end
                end

                READ_UPPER_BYTE: begin
                    data_out[15:8] <= data_input_pins;
                    next_state <= READ_COMPLETE;
                end

                READ_COMPLETE: begin
                    read_enable <= 1'b0;
                    memory_ready <= 1'b1;
                    next_state <= IDLE;
                end

                // UART Receive Operation - Write Address Lower Byte
                UART_RECEIVE_ADDRESS: begin
                    iovalue <= 8'b11111111;  // Set all uio pins to output mode
                    register_enable <= 1'b1;  // Enable register
                    lower_bit <= 1'b1;  // Indicate lower byte
                    upper_bit <= 1'b0;  // Indicate not upper byte
                    data_output_pins <= uart_memory_address[7:0];  // Output lower byte of address
                    next_state <= UART_WAIT_LOWER_BYTE;  // Wait for the lower byte write to complete
                end

                // UART Wait for Lower Byte Write to Complete
                UART_WAIT_LOWER_BYTE: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= UART_RECEIVE_ADDRESS_UPPER;  // Proceed to upper byte
                    end else begin
                        next_state <= UART_WAIT_LOWER_BYTE;  // Continue waiting
                    end
                end

                // UART Receive Operation - Write Address Upper Byte
                UART_RECEIVE_ADDRESS_UPPER: begin
                    lower_bit <= 1'b0;  // Indicate not lower byte
                    upper_bit <= 1'b1;  // Indicate upper byte
                    data_output_pins <= uart_memory_address[15:8];  // Output upper byte of address
                    next_state <= UART_WAIT_UPPER_BYTE;  // Wait for the upper byte write to complete
                end

                // UART Wait for Upper Byte Write to Complete
                UART_WAIT_UPPER_BYTE: begin
                    if (wait_counter >= WAIT_CYCLES) begin
                        next_state <= UART_RECEIVE_DATA;  // Proceed to write data
                    end else begin
                        next_state <= UART_WAIT_UPPER_BYTE;  // Continue waiting
                    end
                end

                // UART Receive Operation - Write Data
                UART_RECEIVE_DATA: begin
                    register_enable <= 1'b0;  // Disable register for data write
                    lower_bit <= 1'b1;  // Set to write lower byte of data
                    upper_bit <= 1'b0;  // Indicate not upper byte
                    data_output_pins <= data_received;  // Output the received UART data
                    write_enable <= 1'b1;
                    next_state <= UART_WAIT_DATA_WRITE;  // Wait for the data write to complete
                end

                // UART Wait for Data Write to Complete
                UART_WAIT_DATA_WRITE: begin
                    if (write_complete) begin  // Ensure data write is complete
                       write_enable <= 1'b0;
                        next_state <= READ_COMPLETE;  // Go to read complete state or next appropriate state
                    end else begin
                        next_state <= UART_WAIT_DATA_WRITE;  // Continue waiting
                    end
                end

                default: begin
                    next_state <= IDLE; 
                end
            endcase
        end
    end
endmodule


Reference solution:
rtl/generated.v: 	reg [15:0] current_address; //!!!CURRENT INSTRUCTION ADDRESS!!!
	reg [15:0] current_instruction;

	reg [15:0] registers[7:0];

	wire [3:0] opcode;
	wire [2:0] settings;
	wire [2:0] reg1, reg2, reg_out;
	wire [8:0] imm_upper;
	wire [7:0] imm_lower;
	wire [4:0] kreg1;
	wire [1:0] kreg1_extended;
	wire [1:0] ksettings;

	reg [2:0] alu_mode;
	reg [15:0] alu_a, alu_b;
	wire [15:0] alu_result;
	wire eF, gaF;

	assign opcode = current_instruction[3:0];
	assign settings = current_instruction[6:4];
	assign reg1 = current_instruction[9:7];
	assign reg2 = current_instruction[12:10];
	assign reg_out = current_instruction[15:13];
	assign imm_lower = current_instruction[15:8];
	assign imm_upper = current_instruction[15:7];
	assign kreg1 = current_instruction[11:7];
	assign kreg1_extended = current_instruction[13:12];
	assign ksettings = current_instruction[15:14];

	reg [64*5-1:0] keccak_registers;
	wire [63:0] keccak_output;

	keccak_alu keccak_alu (
			.registers(keccak_registers),
			.mode(ksettings),
			.keccak_output(keccak_output)
	);

	x3q16alu ALU (
			.a(alu_a),
			.b(alu_b),
			.mode(alu_mode),
			.result(alu_result),
			.equal_flag(eF),
			.greater_a_flag(gaF)
	);
	
	reg uart_send, uart_set;
	reg [12:0]uart_data;
	wire uart_busy;
	assign set_rx_speed = uart_set;
	assign rx_speed = uart_data;
	uart_tx uart (
		.clk(clk),
		.reset(reset),
		.data(uart_data),
		.send(uart_send),
		.set(uart_set),
		.tx_reg(tx),
		.busy(uart_busy)
	);

	integer i;
	reg [2:0] execution_stage;
	reg jump_con;
	always @(posedge clk or posedge reset) begin
		if (reset) begin
			//reset
			for (i = 0; i < 8; i = i + 1) begin
				registers[i] <= 16'b0;
			end
			current_address <= 16'h0000;
			current_instruction <= 16'h0000;
			request_address <= 16'h0000;
			request_type <= 1'b0;
			request <= 1'b1;
			data_out <= 16'b0;
			uart_send <= 1'b0;
			execution_stage <= 3'b000;
			alu_a <= 16'b0;
			alu_b <= 16'b0;
			alu_mode <= 3'b0;
			jump_con <= 1'b0;
			uart_send <= 1'b0;
			uart_set <= 1'b0;
			uart_data <= 16'b0;
			keccak_registers <= 320'b0;
		end else begin
			if (uart_inbound) begin
				registers[1][0] <= 1'b1;
			end

			if (memory_ready) begin
				registers[1][1] <= 1'b1;
			end
			registers[0] <= 16'b0;
			request <= 1'b0;
			uart_send <= 1'b0;
			uart_set <= 1'b0;

			
			// execution
			case (execution_stage)
				3'b000: begin  // load/setup operation stage 1
					if (memory_ready) begin
						current_instruction <= memory_in;
						current_address <= request_address;
						alu_a <= request_address;
						alu_b <= 16'h1;
						execution_stage <= 3'b101;
					end
				end
				3'b001: begin  //operation stage 1
					case (opcode)
						4'b0000: execution_stage <= 3'b100;  //No Operation
						4'b0001: begin  //ALU
							alu_mode <= settings;
							alu_a <= registers[reg1];
							alu_b <= registers[reg2];
							execution_stage <= 3'b010;


						end
						4'b0010: begin  //ALUI
							alu_mode <= settings[0] ? 3'b010 : 3'b000;
							alu_a <= registers[2];
							alu_b <= {8'h00, imm_lower};
							execution_stage <= 3'b010;
						end
						4'b0011: begin  //Keccak ALU
							keccak_registers[4*64+:64] <= keccak_output;
							execution_stage <= 3'b100;
						end
						4'b0100: begin  //Jump
							if (reg_out != 3'b000) registers[reg_out] <= current_address;
							if (settings == 3'b110) request <= 1'b1;
							else
								case (settings)
									3'b000:  jump_con <= 1'b1;
									3'b001:  jump_con <= registers[1][4];
									3'b010:  jump_con <= registers[1][2];
									3'b011:  jump_con <= ~registers[1][2];
									3'b100:  jump_con <= registers[1][1];
									3'b101:  jump_con <= registers[1][0];
									3'b111:  jump_con <= registers[1][3];
									default: jump_con <= 1'b0;
								endcase
							execution_stage <= 3'b010;
						end
						4'b0101: begin  //Load
							alu_a <= current_address;
							if (settings[0] == 1) begin
								request_address <= registers[reg1];
								alu_b <= 16'h1;
							end else alu_b <= 16'h2;
							request <= 1'b1;
							execution_stage <= 3'b010;
						end
						4'b0110: begin  //Store
							data_out <= registers[reg2];
							alu_a <= current_address;
							if (settings[0] == 1) begin
								request_address <= registers[reg1];
								request_type <= 1'b1;
								alu_b <= 16'h1;
							end else alu_b <= 16'h2;
							request <= 1'b1;
							execution_stage <= 3'b010;
						end
						4'b0111: begin //Load Immediate
							registers[settings] <= {imm_upper, 7'b0};
							execution_stage <= 3'b100;
						end
						4'b1000: begin //Uart Call
							if (~uart_busy) begin
								if (settings[0]) uart_set <= 1'b1; else uart_send <= 1'b1;
								uart_data <= registers[reg1][12:0];
								execution_stage <= 3'b100;
							end
						end
						4'b1001: begin  //Keccak load/unload
							alu_a <= current_address;
							alu_b <= 16'b1;
							if (ksettings == 0) begin  //load
								request_address <= registers[settings];
								request <= 1'b1;
							end else begin  // unload
								data_out <= keccak_registers[kreg1*64+kreg1_extended*16+:16];
								request_address <= registers[settings];
								request_type <= 1'b1;
								request <= 1'b1;
							end
							execution_stage <= 3'b010;
						end
					endcase
				end
				3'b010: begin  // operation stage 2
					case (opcode)
						4'b0001: begin  //ALU
							if (reg_out != 3'b000) begin
								registers[reg_out] <= alu_result;
							end
							registers[1][3] <= eF;
							registers[1][2] <= gaF;
							registers[1][4] <= alu_result == 16'h0000;
							execution_stage <= 3'b100;
						end
						4'b0010: begin //ALUI
							//$display("ALU, A: %h, B: %h, R: %h", alu_a, alu_b, alu_result);
							//$display("reg_out: %h", current_instruction[7:5]);
							if (current_instruction[7:5] != 3'b000) begin
								registers[current_instruction[7:5]] <= alu_result;
							end
							registers[1][3] <= eF;
							registers[1][2] <= gaF;
							registers[1][4] <= alu_result == 16'h0000;
							execution_stage <= 3'b100;
						end
						4'b0100: begin  //Jump
							if (settings == 3'b110) begin
								if (memory_ready) begin
									request_address <= memory_in;
									execution_stage <= 3'b100;
								end
							end else begin
								if (jump_con) begin
									request_address <= registers[reg1];
								end
								execution_stage <= 3'b100;
							end
						end
						4'b0101: begin  //Load
							if (memory_ready == 1) begin
								if (settings[0] == 1) begin
									registers[reg_out] <= memory_in;
									request_address <= alu_result;
									execution_stage <= 3'b100;
								end else begin
									request_address <= memory_in;
									request <= 1'b1;
									execution_stage <= 3'b011;
								end
							end
						end
						4'b0110: begin  //Store
							if (settings[0] == 1) begin
								if (write_complete) begin
									request_address <= alu_result;
									execution_stage <= 3'b100;
								end
							end else begin
								if (memory_ready) begin
									request_address <= memory_in;
									request_type <= 1'b1;
									request <= 1'b1;
									execution_stage <= 3'b011;
								end
							end
						end
						4'b1001: begin  //Keccak load/unload
							if (ksettings == 0) begin  //load
								if (memory_ready) begin
									keccak_registers[kreg1*64+kreg1_extended*16+:16] <= memory_in;
									request_address <= alu_result;
									execution_stage <= 3'b100;
								end
							end else begin  // unload/store
								if (write_complete) begin
									request_address <= alu_result;
									execution_stage <= 3'b100;
								end
							end
						end
					endcase
				end
				3'b011: begin  // operation stage 3
					if (opcode == 4'b0101) begin  // load or store
						if (memory_ready) begin
							registers[reg_out] <= memory_in;
							request_address <= alu_result;
							execution_stage <= 3'b100;
						end
					end else begin
						if (write_complete) begin
							request_address <= alu_result;
							execution_stage <= 3'b100;
							request_type <= 1'b0;
						end
					end
				end
				3'b100: begin  // post operation / send next load request
					execution_stage <= 3'b000;
					request_type <= 1'b0;
					request <= 1'b1;
					data_out <= 16'b0;
					alu_mode <= 3'b000;

					
					$display("Current Instr: %b", current_instruction);
					$display("Current Addr: %h", current_address);
					$display("R0: %h", registers[0]);
					$display("R1: %h", registers[1]);
					$display("R2: %h", registers[2]);
					$display("R3: %h", registers[3]);
					$display("R4: %h", registers[4]);
					$display("R5: %h", registers[5]);
					$display("R6: %h", registers[6]);
					$display("R7: %h", registers[7]);
					$display("---------------------------------");
					

				end
				3'b101: begin // Setup stage 2
					request_address <= alu_result;
					execution_stage <= 3'b001;
				end
			endcase
			registers[0] <= 16'b0;

		end
	end