Ты — эксперт по разработке игр для NES (Famicom) на ассемблере MOS 6502.
Твоя задача — написать процедуру инициализации и запуска игры для многоигровки (мультикартриджа) "9999 в 1".

### Окружение и Архитектура:
*   **Маппер:** MMC1 (Плата SNROM).
*   **Память:** 256 КБ PRG-ROM (16 банков по 16 КБ), 8 КБ CHR-RAM, 8 КБ WRAM ($6000–$7FFF).
*   **Инструменты:** Ассемблер ca65 и линкер ld65 под Linux.
*   **Текущее состояние:** Меню выбора игр успешно компилируется и работает в последнем фиксированном банке ($C000–$FFFF).
Вся навигация и выбор происходят в процедуре `_func_ecef`.

### Постановка задачи:
Необходимо реализовать код загрузчика игры (Bootloader), который считывает выбор пользователя, настраивает маппер MMC1 и передает управление игре.

Так как игра (например, Super Mario Bros) может занимать 32 КБ и переключать оба окна PRG (включая область $C000–$FFFF),
код загрузчика **обязан выполняться из оперативной памяти (RAM) по адресу $0600**, иначе при переключении банков произойдет краш.

### Пошаговый алгоритм загрузчика:
1.  **Получение ID игры:** Считать индекс выбранного пункта меню из RAM по адресу `$001c` (значение от 0 до 255).
2.  **Поиск в таблице повторений:** Использовать этот индекс для чтения из `RepeatTable` (Таблица повторений), чтобы получить реальный номер игры (от 1 до 9).
3.  **Поиск параметров игры:** По реальному номеру игры получить из `GameConfigTable` параметры: стартовый PRG-банк, режим зеркалирования (mirroring) и адрес вектора сброса игры (Reset Vector).
4.  Сохранение параметров (и chr и prg) mmc1 в zero page, не затронь $001c. Свободны адреса $0032 - $003F.
5.  **Копирование CHR-данных:** Так как используется CHR-RAM, необходимо ПРЕДВАРИТЕЛЬНО скопировать графические тайлы выбранной игры из PRG-ROM в PPU CHR-RAM (через регистры $2006/$2007).
КРИТИЧЕСКИ ВАЖНО - PRG И CHR могут находится в разных банках. Сналала переключаем на банк, где находится CHR Выбранной игры.
6.  После копирования CHR, переключаем на банк где находится prg игры.
    *   Устанавливаем режим правильного зеркалирования и режима PRG (32 КБ или 16 КБ в зависимости от игры).
    *   Записать стартовый номер PRG-банка игры в регистр PRG MMC1 ($E000).
7.  **Старт игры:** Выполнить косвенный переход `jmp` на Reset-вектор запущенной игры.

### Критические ограничения интеграции (ВАЖНО):
1.  **Запрет смещения кода:** Меню очень чувствительно к адресам. Любое смещение существующих функций разрушит его.
Код новых процедур и таблиц нужно разместить в самом внизу сегмента CODE. Места там достаточно.
2.  **Точка внедрения:** Переход на загрузчик должен происходить из метки `_label_ed25` (внутри процедуры `_func_ecef`).
Замени существующий там старый код маппера 212 на вызов процедуры копирования загрузчика в RAM и последующий `jmp $0600`.
Оставшиеся байты старого кода в этой секции заполни инструкциями `nop`, чтобы длина блока не изменилась ни на один байт!

### Строгие правила синтаксиса ca65 (MOS 6502):
1.  **Локальные метки:** Должны начинаться ТОЛЬКО с символа `@` (например, `@copy_loop:` или `@bit_loop:`).
Начинать локальные метки с точки `.` категарически ЗАПРЕЩЕНО.
2.  **16-битные адреса:** При загрузке старшего/младшего байтов адресов меток всегда используй операторы `<` и `>`
(например: `lda #<RepeatTable`, `ldx #>RepeatTable`), чтобы избежать ошибок компиляции "range error".

### Что нужно выдать в ответе:
1.  Код структуры таблиц данных (`RepeatTable` и `GameConfigTable).
2.  Код процедуры копирования загрузчика из ROM в RAM ($0600).
3.  Сам код загрузчика, адаптированный для работы по адресу $0600.
4.  Точный патч для `_label_ed25` с заполнением `nop`, демонстрирующий безопасный прыжок на `$0600`.

ТАБЛИЦА ПОВТОРЕНИЙ ИГР
.byte 01,02,03,04,05,02,01,03,05,03,05,02,03,05,03,01
.byte 02,03,06,05,02,01,03,05,03,05,02,03,05,03,01,02
.byte 03,04,05,02,01,03,05,03,05,02,03,05,03,01,02,03
.byte 06,05,02,01,03,05,03,05,02,03,05,03,01,02,03,04
.byte 05,02,01,03,05,03,05,02,03,05,03,01,07,03,06,05
.byte 02,01,03,05,03,05,02,03,05,03,01,02,03,05,05,02
.byte 01,03,05,03,05,02,03,05,03,01,02,03,05,05,08,01
.byte 03,05,03,05,02,03,05,03,01,02,03,05,05,02,01,03
.byte 05,03,05,02,03,05,03,01,02,03,05,05,02,01,03,05
.byte 03,05,02,03,05,03,01,02,03,05,05,02,01,03,05,03
.byte 05,02,03,05,03,01,02,03,05,05,02,01,03,05,03,05
.byte 02,03,05,03,01,02,03,05,05,02,01,03,05,03,05,02
.byte 03,05,03,01,02,03,05,05,02,01,03,05,03,05,02,03
.byte 05,03,01,02,03,05,05,02,01,03,05,03,05,09,03,05
.byte 03,01,02,03,05,05,02,01,03,05,03,05,02,03,05,03
.byte 01,02,03,05,05,02,01,03,05,03,05,02,03,05,03,01


СПИСОК ИГР

№,Название,PRG,CHR,Mirroring (по данным)
01,Super Mario Bros,32 KB,8 KB,Horizontal
02,Battle City,16 KB,8 KB,Vertical
03,Galaxian,8 KB,8 KB,Vertical
04,Lunar Ball,16 KB,8 KB,Vertical
05,Duck Hunt,16 KB,8 KB,Horizontal
06,Wild Gunman,16 KB,8 KB,Horizontal
07,Balloon Fight,16 KB,8 KB,Horizontal
08,Bomberman,16 KB,8 KB,Horizontal
09,Ice Climber,16 KB,8 KB,Vertical


CFG ФАЙЛ СБОРКИ

MEMORY {
    # 16 байт заголовка iNES
    HEADER:  start = $0000, size = $0010, file = %O, fill = yes;

    # PRG Банки по 16 Кб ($8000 - это адрес их проекции в CPU при переключении)
    PRG_0:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_1:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_2:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_3:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_4:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_5:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_6:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_7:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_8:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_9:   start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_10:  start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_11:  start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_12:  start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_13:  start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;
    PRG_14:  start = $8000, size = $4000, file = %O, fill = yes, fillval = $FF;

    # PRG Банк 15 ($C000) для Меню
    PRG_15:  start = $C000, size = $3F00, file = %O, fill = yes, fillval = $FF;
    PRG_15_INIT: start = $FF00, size = $00FA, file = %O, fill = yes, fillval = $FF;
    VECTORS: start = $FFFA, size = $0006, file = %O, fill = yes, fillval = $FF;
}


SEGMENTS {
    HEADER:       load = HEADER,       type = ro;

    # Банк 0
    TILES:        load = PRG_0,        type = ro, start = $8000;
    SMB_CHR:      load = PRG_0,        type = ro, start = $A000;

    # Банк 1
    GALAXIAN_PRG: load = PRG_1,        type = ro, start = $8000;
    GALAXIAN_CHR: load = PRG_1,        type = ro, start = $A000;

    # Банки 2-3 (Марио)
    SMB_PRG_1:    load = PRG_2,        type = ro;
    SMB_PRG_2:    load = PRG_3,        type = ro;

    # Танчики и Лунар Бол
    BC_PRG:       load = PRG_4,        type = ro;
    BC_LB_CHR:    load = PRG_5,        type = ro;  # Сюда инклудите .incbin "battlecity.chr" и "lunarball.chr" подряд
    LB_PRG:       load = PRG_6,        type = ro;

    # Утки и Ковбои
    DH_PRG:       load = PRG_7,        type = ro;
    DH_WG_CHR:    load = PRG_8,        type = ro;  # Подряд CHR уток и ковбоев
    WG_PRG:       load = PRG_9,        type = ro;

    # Шарики и Бомбермен
    BF_PRG:       load = PRG_10,       type = ro;
    BF_BM_CHR:    load = PRG_11,       type = ro;  # Подряд CHR шариков и бомбера
    BM_PRG:       load = PRG_12,       type = ro;

    # Айс Клаймбер
    IC_PRG:       load = PRG_13,       type = ro;
    IC_CHR:       load = PRG_14,       type = ro, start = $8000; # Займет только первую половину банка 14

    # Меню
    CODE:         load = PRG_15,       type = ro, start = $C000;
    MMC1_INIT:    load = PRG_15_INIT,  type = ro, start = $FF00;
    VECTORS:      load = VECTORS,      type = ro, start = $FFFA;
}


_func_ecef:
  lda z:_var_0022                ; $ECEF  A5 22
  ldy #$00                       ; $ECF1  A0 00
  sty z:_var_0022                ; $ECF3  84 22
  tay                            ; $ECF5  A8
  and #$52                       ; $ECF6  29 52
  cmp #$52                       ; $ECF8  C9 52
  beq _label_ed16                ; $ECFA  F0 1A
  tya                            ; $ECFC  98
  and #$20                       ; $ECFD  29 20
  bne _label_ed1c                ; $ECFF  D0 1B
  tya                            ; $ED01  98
  and #$40                       ; $ED02  29 40
  bne _label_ed1f                ; $ED04  D0 19
  tya                            ; $ED06  98
  and #$80                       ; $ED07  29 80
  bne _label_ed25                ; $ED09  D0 1A
  tya                            ; $ED0B  98
  and #$08                       ; $ED0C  29 08
  bne _label_ed22                ; $ED0E  D0 12
  tya                            ; $ED10  98
  and #$04                       ; $ED11  29 04
  bne _label_ed19                ; $ED13  D0 04
  rts


_label_ed25:
  sei                            ; $ED25  78
  cld                            ; $ED26  D8
  jsr _func_c1ab                 ; $ED27  20 AB C1
  ldx #$FF                       ; $ED2A  A2 FF

