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.

// SPDX-FileCopyrightText: © 2024 Uri Shaked <uri@wokwi.com>
// SPDX-License-Identifier: MIT

`default_nettype none

module tt_um_urish_spell (
    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,      // will go high when the design is enabled
    input  wire       clk,      // clock
    input  wire       rst_n     // reset_n - low to reset
);

  localparam StateFetch = 3'd0;
  localparam StateFetchData = 3'd1;
  localparam StateExecute = 3'd2;
  localparam StateStore = 3'd3;
  localparam StateDelay = 3'd4;
  localparam StateSleep = 3'd5;
  localparam StateStop = 3'd6;

  localparam REG_PC = 2'd0;
  localparam REG_SP = 2'd1;
  localparam REG_EXEC = 2'd2;
  localparam REG_STACK_TOP = 2'd3;

  wire o_sleep = state == StateSleep;
  wire o_stop = state == StateStop || state == StateSleep;
  wire o_wait_delay = state == StateDelay;
  reg o_shift_out;

  wire [7:0] porta_oe;
  wire [7:0] porta_out;
  assign uo_out = (
    (~porta_oe & {4'b0000, o_shift_out, o_wait_delay, o_stop, o_sleep})
    | (porta_oe & porta_out)
  );

  wire i_run = ui_in[0];
  wire i_step = ui_in[1];
  wire i_load = ui_in[2];
  wire i_dump = ui_in[3];
  wire i_shift_in = ui_in[4];
  wire [1:0] i_reg_sel = ui_in[6:5];

  reg past_i_run;
  reg [2:0] state;
  reg [7:0] pc;
  reg [4:0] sp;
  reg [7:0] opcode;
  reg [7:0] memory_input;
  reg [7:0] stack[31:0];

  wire [7:0] next_pc;
  wire [4:0] next_sp;
  wire [1:0] stack_write_count;
  wire [7:0] set_stack_top;
  wire [7:0] set_stack_belowtop;
  wire memory_write_en;
  wire memory_write_type_data;
  wire [7:0] memory_write_addr;
  wire [7:0] memory_write_data;
  wire [7:0] delay_amount;
  wire sleep;
  wire stop;

  // shift register for loading data / dumping debug info
  reg [7:0] shift_reg;

  // Out of order execution
  reg single_step;
  reg out_of_order_exec;

  wire [4:0] stack_top_index = sp - 1;
  wire [7:0] stack_top = stack[stack_top_index];

  // Memory related registers
  reg mem_select;
  reg mem_type_data;
  reg [7:0] mem_addr;
  reg [7:0] mem_write_value;
  reg mem_write_en;
  wire [7:0] mem_read_value;
  wire mem_data_ready;

  // Delay related registers
  reg [23:0] cycles_per_ms;
  reg [23:0] delay_cycles;
  reg [7:0] delay_counter;

  // Debug stuff
  reg [63:0] reg_name;
  reg [63:0] state_name;

  // To avoid linter warnings about unused wires
  wire _unused_ok = &{1'b0, ena, ui_in[7], state_name, reg_name, 1'b0};

  always @(*) begin
    case (state)
      StateFetch: state_name = "Fetch";
      StateFetchData: state_name = "FetchDat";
      StateExecute: state_name = "Execute";
      StateStore: state_name = "Store";
      StateDelay: state_name = "Delay";
      StateSleep: state_name = "Sleep";
      StateStop: state_name = "Stop";
      default: state_name = "Invalid";
    endcase
  end

  always @(*) begin
    case (i_reg_sel)
      REG_PC: reg_name = "PC";
      REG_SP: reg_name = "SP";
      REG_EXEC: reg_name = "Exec";
      REG_STACK_TOP: reg_name = "StackTop";
    endcase
  end

  spell_execute exec (
      .opcode(opcode),
      .pc(pc),
      .sp(sp),
      .stack_top(stack_top),
      .stack_belowtop(stack[sp-2]),
      .memory_input(memory_input),
      .next_pc(next_pc),
      .next_sp(next_sp),
      .out_of_order_exec(out_of_order_exec),
      .stack_write_count(stack_write_count),
      .set_stack_top(set_stack_top),
      .set_stack_belowtop(set_stack_belowtop),
      .memory_write_en(memory_write_en),
      .memory_write_type_data(memory_write_type_data),
      .memory_write_addr(memory_write_addr),
      .memory_write_data(memory_write_data),
      .delay_amount(delay_amount),
      .sleep(sleep),
      .stop(stop)
  );

  spell_mem mem (
      .rst_n(rst_n),
      .clk(clk),
      .select(mem_select),
      .addr(mem_addr),
      .data_in(mem_write_value),
      .memory_type_data(mem_type_data),
      .write(mem_write_en),
      .data_out(mem_read_value),
      .data_ready(mem_data_ready),
      // IO
      .porta_out(porta_out),
      .porta_oe(porta_oe),
      .portb_in(uio_in),
      .portb_out(uio_out),
      .portb_oe(uio_oe)
  );

  function is_data_opcode(input [7:0] opcode_to_test);
    is_data_opcode = (opcode_to_test == "?" || opcode_to_test == "r");
  endfunction

  integer j;

  // Main logic
  always @(posedge clk) begin
    if (~rst_n) begin
      state <= StateSleep;
      pc    <= 0;
      sp    <= 0;
      for (j = 0; j < 32; j++) stack[j] <= 0;
      opcode <= 0;
      mem_select <= 0;
      mem_write_en <= 0;
      single_step <= 0;
      out_of_order_exec <= 0;
      cycles_per_ms <= 24'd10000;  /* we assume a 10MHz clock */
      delay_cycles <= 0;
      shift_reg <= 0;
      o_shift_out <= 0;
      past_i_run <= 0;
    end else begin
      shift_reg   <= {shift_reg[6:0], i_shift_in};
      o_shift_out <= shift_reg[7];
      past_i_run  <= i_run;

      if (i_load) begin
        case (i_reg_sel)
          REG_PC: pc <= shift_reg;
          REG_SP: sp <= shift_reg[4:0];
          REG_EXEC: begin
            opcode <= shift_reg;
            state <= is_data_opcode(shift_reg) ? StateFetchData : StateExecute;
            single_step <= 1;
            out_of_order_exec <= 1;
          end
          REG_STACK_TOP: begin
            stack[sp] <= shift_reg;
            sp <= sp + 1;
          end
        endcase
      end

      if (i_dump) begin
        case (i_reg_sel)
          REG_PC: shift_reg <= pc;
          REG_SP: shift_reg <= {3'b000, sp};
          REG_EXEC: shift_reg <= opcode;
          REG_STACK_TOP: shift_reg <= stack[sp-1];
        endcase
      end

      if (i_run && !past_i_run && (state == StateSleep || state == StateStop)) begin
        single_step <= i_step;
        out_of_order_exec <= 0;
        state <= StateFetch;
      end

      case (state)
        StateFetch: begin
          // Read next instruction from code memory
          mem_select <= 1;
          mem_type_data <= 0;
          mem_addr <= pc;
          mem_write_en <= 0;
          if (mem_select && mem_data_ready) begin
            mem_select <= 0;
            opcode <= mem_read_value;
            state <= is_data_opcode(mem_read_value) ? StateFetchData : StateExecute;
          end
        end
        StateFetchData: begin
          // Read data for instruction from either code or data memory
          mem_select <= 1;
          mem_type_data <= (opcode == "r") ? 1'b1 : 1'b0;
          mem_addr <= stack_top;
          mem_write_en <= 0;
          if (mem_select && mem_data_ready) begin
            mem_select <= 0;
            memory_input <= mem_read_value;
            state <= StateExecute;
          end
        end
        StateExecute: begin
          // Execute a single instruction
          pc <= next_pc;
          sp <= next_sp;
          mem_type_data <= memory_write_type_data;
          mem_addr <= memory_write_addr;
          mem_write_value <= memory_write_data;
          if (stack_write_count == 1 || stack_write_count == 2) begin
            stack[next_sp-1] <= set_stack_top;
          end
          if (stack_write_count == 2) begin
            stack[next_sp-2] <= set_stack_belowtop;
          end
          if (memory_write_en) begin
            state <= StateStore;
          end else if (stop || single_step) begin
            state <= StateStop;
          end else if (sleep) begin
            state <= StateSleep;
          end else if (delay_amount != 8'b0 && cycles_per_ms != 24'b0) begin
            delay_counter <= delay_amount - 1;
            delay_cycles <= 0;
            state <= StateDelay;
          end else begin
            state <= StateFetch;
          end
        end
        StateStore: begin
          // Store data from instruction into either code or data memory
          mem_select   <= 1;
          mem_write_en <= 1;
          if (mem_data_ready) begin
            mem_select <= 0;
            mem_write_en <= 0;
            state <= single_step ? StateSleep : StateFetch;
          end
        end
        StateSleep: begin
          // The only way to leave this state is via external intervention.
        end
        StateStop: begin
          // The only way to leave this state is via external intervention.
        end
        StateDelay: begin
          if (delay_cycles + 1 >= cycles_per_ms) begin
            delay_counter <= delay_counter - 1;
            delay_cycles  <= 0;
            if (delay_counter == 0) begin
              state <= single_step ? StateSleep : StateFetch;
            end
          end else begin
            delay_cycles <= delay_cycles + 1;
          end
        end
        default: state <= 3'bx;
      endcase
    end
  end

`ifdef FORMAL
  reg f_init = 1;
  always @(posedge clk) begin
    if (f_init) assume (~rst_n);
    if (rst_n) begin
      assert (!sleep || !stop);
      assert(
        state == StateFetch ||
        state == StateFetchData ||
        state == StateExecute ||
        state == StateStore ||
        state == StateDelay ||
        state == StateSleep ||
        state == StateStop
      );
      if (state == StateDelay) begin
        assume (cycles_per_ms > 0);
        assert (delay_counter != 8'hff);
        assert (delay_cycles < cycles_per_ms);
      end
      if (state != StateFetch && state != StateFetchData && state != StateStore) begin
        assert (!mem_select);
      end
      if (state != StateStore) begin
        assert (!mem_write_en);
      end
    end
    f_init <= 0;
  end
`endif  /* FORMAL */

endmodule


// SPDX-FileCopyrightText: © 2021 Uri Shaked <uri@wokwi.com>
// SPDX-License-Identifier: MIT

`default_nettype none

module spell_execute (
    input wire [7:0] opcode,
    input wire [7:0] pc,
    input wire [4:0] sp,
    input wire [7:0] stack_top,
    input wire [7:0] stack_belowtop,
    input wire [7:0] memory_input,
    input wire out_of_order_exec,
    output reg [7:0] next_pc,
    output reg [4:0] next_sp,
    output reg [1:0] stack_write_count,
    output reg [7:0] set_stack_top,
    output reg [7:0] set_stack_belowtop,
    output reg memory_write_en,
    output reg memory_write_type_data,
    output reg [7:0] memory_write_data,
    output reg [7:0] memory_write_addr,
    output reg [7:0] delay_amount,
    output reg sleep,
    output reg stop
);

  always @(*) begin
    next_pc = out_of_order_exec ? pc : pc + 8'd1;
    next_sp = sp;
    stack_write_count = 2'd0;
    set_stack_top = 8'dx;
    set_stack_belowtop = 8'dx;
    memory_write_en = 1'b0;
    memory_write_type_data = 1'b0;
    memory_write_addr = 8'dx;
    memory_write_data = 8'dx;
    sleep = 0;
    stop = 0;
    delay_amount = 0;

    case (opcode)
      "+": begin
        set_stack_top = stack_belowtop + stack_top;
        stack_write_count = 1;
        next_sp = sp - 1;
      end
      "-": begin
        set_stack_top = stack_belowtop - stack_top;
        stack_write_count = 1;
        next_sp = sp - 1;
      end
      "&": begin
        set_stack_top = stack_belowtop & stack_top;
        stack_write_count = 1;
        next_sp = sp - 1;
      end
      "^": begin
        set_stack_top = stack_belowtop ^ stack_top;
        stack_write_count = 1;
        next_sp = sp - 1;
      end
      "|": begin
        set_stack_top = stack_belowtop | stack_top;
        stack_write_count = 1;
        next_sp = sp - 1;
      end
      ">": begin
        set_stack_top = {1'b0, stack_top[7:1]};
        stack_write_count = 1;
      end
      "<": begin
        set_stack_top = {stack_top[6:0], 1'b0};
        stack_write_count = 1;
      end
      "=": begin
        next_pc = stack_top;
        next_sp = sp - 1;
      end
      "@": begin
        if (stack_belowtop != 8'd0) begin
          next_pc = stack_top;
          next_sp = sp - 1;
          set_stack_top = stack_belowtop - 1;
          stack_write_count = 1;
        end else begin
          next_sp = sp - 2;
        end
      end
      ",": begin
        delay_amount = stack_top;
        next_sp = sp - 1;
      end
      "2": begin
        set_stack_top = stack_top;
        stack_write_count = 1;
        next_sp = sp + 1;
      end
      "!": begin
        memory_write_en = 1'b1;
        memory_write_type_data = 1'b0;
        memory_write_addr = stack_top;
        memory_write_data = stack_belowtop;
        next_sp = sp - 2;
      end
      "?", "r": begin
        set_stack_top = memory_input;
        stack_write_count = 1;
      end
      "w": begin
        memory_write_en = 1'b1;
        memory_write_type_data = 1'b1;
        memory_write_addr = stack_top;
        memory_write_data = stack_belowtop;
        next_sp = sp - 2;
      end
      "x": begin
        set_stack_top = stack_belowtop;
        set_stack_belowtop = stack_top;
        stack_write_count = 2;
      end
      "z":   sleep = 1'b1;
      8'hff: stop = 1'b1;
      default: begin
        set_stack_top = opcode;
        stack_write_count = 1;
        next_sp = sp + 1;
      end
    endcase
  end
endmodule


// SPDX-FileCopyrightText: © 2021 Uri Shaked <uri@wokwi.com>
// SPDX-License-Identifier: MIT

`default_nettype none

module spell_mem (
    input wire rst_n,
    input wire clk,
    input wire select,
    input wire [7:0] addr,
    input wire [7:0] data_in,
    input wire memory_type_data,
    input wire write,
    output reg [7:0] data_out,
    output wire data_ready,

    /* IO */
    output wire [7:0] porta_out,
    output wire [7:0] porta_oe, // out enable
    input  wire [7:0] portb_in,
    output wire [7:0] portb_out,
    output wire [7:0] portb_oe  // out enable
);

  wire code_select = select && !memory_type_data;

  wire data_select = select && memory_type_data;
  wire data_mem_select = data_select && (addr < 8'h20 || addr >= 8'h60);
  wire data_io_select = data_select && (addr >= 8'h20 && addr < 8'h60);

  wire mem_select = code_select || data_mem_select;

  wire io_data_ready;
  wire internal_data_ready;
  assign data_ready = io_data_ready | internal_data_ready;

  wire [7:0] io_data_out;
  wire [7:0] internal_data_out;

  spell_mem_io mem_io (
      .rst_n(rst_n),
      .clk(clk),
      .select(data_io_select),
      .addr(addr),
      .data_in(data_in),
      .write(write),
      .data_out(io_data_out),
      .data_ready(io_data_ready),

      /* IO */
      .porta_out(porta_out),
      .porta_oe(porta_oe),
      .portb_in (portb_in),
      .portb_out(portb_out),
      .portb_oe(portb_oe)
  );

  spell_mem_internal mem_internal (
      .rst_n(rst_n),
      .clk(clk),
      .select(mem_select),
      .addr(addr),
      .data_in(data_in),
      .memory_type_data(memory_type_data),
      .write(write),
      .data_out(internal_data_out),
      .data_ready(internal_data_ready)
  );

  always @(*) begin
    if (data_io_select) begin
      data_out = io_data_out;
    end else begin
      data_out = internal_data_out;
    end
  end

endmodule


// SPDX-FileCopyrightText: © 2021-2024 Uri Shaked <uri@wokwi.com>
// SPDX-License-Identifier: MIT

`default_nettype none

module spell_mem_internal (
    input wire rst_n,
    input wire clk,
    input wire select,
    input wire [7:0] addr,
    input wire [7:0] data_in,
    input wire memory_type_data,
    input wire write,
    output wire [7:0] data_out,
    output reg data_ready
);
// >>> Module Implementation Begin

// <<< Module Implementation End
endmodule




// SPDX-FileCopyrightText: © 2021 Uri Shaked <uri@wokwi.com>
// SPDX-License-Identifier: MIT

`default_nettype none

module spell_mem_io (
    input wire rst_n,
    input wire clk,
    input wire select,
    input wire [7:0] addr,
    input wire [7:0] data_in,
    input wire write,
    output reg [7:0] data_out,
    output reg data_ready,

    /* porta */
    output reg [7:0] porta_out,
    output reg [7:0] porta_oe,   // out enable (active high)

    /* porta */
    input  wire [7:0] portb_in,
    output reg  [7:0] portb_out,
    output reg  [7:0] portb_oe    // out enable (active high)
);

  localparam REG_PINB = 8'h36;
  localparam REG_DDRB = 8'h37;
  localparam REG_PORTB = 8'h38;
  localparam REG_PINA = 8'h39;
  localparam REG_DDRA = 8'h3a;
  localparam REG_PORTA = 8'h3b;

  reg past_write;

  always @(posedge clk) begin
    if (~rst_n) begin
      porta_out  <= 8'b00000000;
      porta_oe   <= 8'b00000000;
      portb_out  <= 8'b00000000;
      portb_oe   <= 8'b00000000;
      data_out   <= 8'b0;
      data_ready <= 1'b0;
      past_write <= 1'b0;
    end else begin
      past_write <= select & write;
      if (select) begin
        data_out   <= 8'b0;
        data_ready <= 1'b1;

        case (addr)
          REG_PINB: begin
            if (write) begin
              if (~past_write) portb_out <= portb_out ^ data_in;
            end else begin
              data_out <= portb_in;
            end
          end
          REG_DDRB: begin
            if (write) begin
              portb_oe <= data_in;
            end else begin
              data_out <= portb_oe;
            end
          end
          REG_PORTB: begin
            if (write) begin
              portb_out <= data_in;
            end else begin
              data_out <= portb_out;
            end
          end
          REG_PINA: begin
            if (write) begin
              if (~past_write) porta_out <= porta_out ^ data_in;
            end else begin
              data_out <= 8'h00;
            end
          end
          REG_DDRA: begin
            if (write) begin
              porta_oe <= data_in;
            end else begin
              data_out <= porta_oe;
            end
          end
          REG_PORTA: begin
            if (write) begin
              porta_out <= data_in;
            end else begin
              data_out <= porta_out;
            end
          end
          default: begin
            if (~write) data_out <= 8'hff;
          end
        endcase
      end else data_ready <= 1'b0;
    end
  end
endmodule


/// sta-blackbox

`default_nettype none

module RAM32 (
`ifdef USE_POWER_PINS
    input VPWR,
    input VGND,
`endif
    input CLK,
    input [3:0] WE0,
    input EN0,
    input [4:0] A0,
    input [31:0] Di0,
    output reg [31:0] Do0
);
  reg [31:0] RAM[31:0];

  always @(posedge CLK)
    if (EN0) begin
      Do0 <= RAM[A0];
      if (WE0[0]) RAM[A0][7:0] <= Di0[7:0];
      if (WE0[1]) RAM[A0][15:8] <= Di0[15:8];
      if (WE0[2]) RAM[A0][23:16] <= Di0[23:16];
      if (WE0[3]) RAM[A0][31:24] <= Di0[31:24];
    end else begin
      Do0 <= 32'b0;
    end

endmodule


Reference solution:
rtl/generated.v: 
  localparam data_mem_size = 32;

  wire code_mem_lo_sel = !memory_type_data && addr[7] == 1'b0;
  wire code_mem_hi_sel = !memory_type_data && addr[7] == 1'b1;

  reg code_mem_ready;
  reg [4:0] code_mem_init_addr;

  wire [4:0] code_mem_addr = code_mem_ready ? addr[6:2] : code_mem_init_addr;
  wire [31:0] code_mem_lo_do;
  wire [31:0] code_mem_hi_do;
  wire [31:0] code_mem_di = code_mem_ready ? {data_in, data_in, data_in, data_in} : 32'hffffffff;
  wire [31:0] code_mem_do = code_mem_lo_sel ? code_mem_lo_do : code_mem_hi_do;

  wire [4:0] word_index = {addr[1:0], 3'b000};
  wire [7:0] code_mem_out = code_mem_do[word_index+:8];
  reg [7:0] data_mem_out;
  wire [7:0] data_out_byte = memory_type_data ? data_mem_out : code_mem_out;
  assign data_out = data_ready ? data_out_byte : 8'bx;


  wire we = select && write;
  wire [3:0] we_sel = we ? (1 << addr[1:0]) : 0;
  wire [3:0] code_mem_we0 = code_mem_ready ? we_sel : 4'b1111;

  RAM32 code_mem_lo (
      .CLK(clk),
      .EN0(rst_n),
      .WE0(code_mem_lo_sel || !code_mem_ready ? code_mem_we0 : 4'b0000),
      .A0 (code_mem_addr),
      .Di0(code_mem_di),
      .Do0(code_mem_lo_do)
  );

  RAM32 code_mem_hi (
      .CLK(clk),
      .EN0(rst_n),
      .WE0(code_mem_hi_sel || !code_mem_ready ? code_mem_we0 : 4'b0000),
      .A0 (code_mem_addr),
      .Di0(code_mem_di),
      .Do0(code_mem_hi_do)
  );

  localparam data_mem_bits = $clog2(data_mem_size);
  reg [7:0] data_mem[data_mem_size-1:0];
  wire [data_mem_bits-1:0] data_addr = addr[data_mem_bits-1:0];

  reg [1:0] cycles;

  integer i;

  always @(posedge clk) begin
    if (~rst_n) begin
      cycles <= 0;
      data_ready <= 0;
      data_mem_out <= 0;
      for (i = 0; i < data_mem_size; i++) data_mem[i] <= 8'h00;
      code_mem_ready <= 0;
      code_mem_init_addr <= 0;
    end else begin
      if (!code_mem_ready) begin
        code_mem_init_addr <= code_mem_init_addr + 1;
        if (code_mem_init_addr == 5'b11111) begin
          code_mem_ready <= 1;
        end
      end else if (!select) begin
        data_ready <= 1'b0;
`ifdef SPELL_INTERNAL_MEM_DELAY
        cycles <= 2'b11;
`endif  /* SPELL_INTERNAL_MEM_DELAY */
      end else if (cycles > 0) begin
        cycles <= cycles - 1;
      end else begin
        data_ready <= 1'b1;
        if (write) begin
          if (memory_type_data && addr < data_mem_size) begin
            data_mem[data_addr] <= data_in;
          end
        end else begin
          data_mem_out <= 8'h00;
          if (memory_type_data && addr < data_mem_size) begin
            data_mem_out <= data_mem[data_addr];
          end
        end
      end
    end
  end