; ===== ОСНОВНАЯ ФУНКЦИЯ ПЕЧАТИ =====
.org 0x80090000
ExternalPrint:
        lhu v0,0x0(a0)              ; Читаем 2 байта текста
        nop
        srl v1,v0,0xD               ; Проверяем 13-й бит (система 1-байтовых символов)
        bne v1,zero,MyPrintLineRoutine ; Если установлен - используем кастомную систему
        clear v1
        j PrintBigDMAText           ; Иначе - оригинальная система печати
        nop

; ===== КАСТОМНАЯ СИСТЕМА ПЕЧАТИ =====
MyPrintLineRoutine:
        addiu sp,sp,-0x50           ; Сохраняем контекст
        sw s4,0x38(sp)
        move s4,r4                  ; s4 = адрес текста для чтения
        sw s0,0x28(sp)
        move s0,r5                  ; s0 = параметр X
        sw s1,0x2c(sp)
        move s1,r6                  ; s1 = параметр Y
        sw s3,0x34(sp)

; ===== ИНИЦИАЛИЗАЦИЯ ПАРАМЕТРОВ ТЕКСТА =====
        andi v0,v0,0xff 
        addiu s4,s4,0x2             ; Сдвигаем указатель текста на +2 байта
        
        lui s3,MyAddr
        sw v0,-0x10(s3)             ; Сохраняем счётчик байтов @ 8008fff0
        sh zero,-0xE(s3)            ; Очищаем счётчик символов @ 8008fff2

; ===== ИНИЦИАЛИЗАЦИЯ DMA ЦЕПОЧЕК =====
        lui s3,0x1f80
        ori s3,s3,0x3d0             ; s3 = 1f8003d0 - команда копирования спрайта в scratch

        lui t0,0xff
        ori t0,t0,0xffff            ; t0 = 00FFFFFF (маска)

        andi r4,r7,0xff             ; Режим текста (цвет и тень)
        lui r7, 0x8008              ; r7 = 80080000
        lui r6, 0xff00              ; r6 = FF000000 (маска)

        ; ЗАГРУЗКА ЦЕПОЧКИ ФОРМИРОВАНИЯ СИМВОЛОВ
        addiu t1,r7,-0x31a8         ; t1 = адрес цепочки формирования (8007ce58)
        lw v1, -0x31a8(r7)          ; v1 = текущая свободная цепочка формирования
        lbu r5,0x60(sp)             ; Флаг тени из стека

        and r6,v1,r6                ; r6 = старшие байты цепочки (FFxxxxxx)
        andi r5,r5,0xff             ; Очищаем режим текста
        and v1,v1,t0                ; v1 = младшие байты цепочки (00xxxxxx)
        or s5,v1,v0                 ; s5 = адрес текущей цепочки формирования (80xxxxxx)

        ; ОБНОВЛЕНИЕ СЧЁТЧИКА И ЦЕПОЧКИ
        lw v0,0x4(t1)               ; Счётчик команд DMA
        lw v1,0x0(s5)               ; Следующая свободная цепочка
        addiu v0,v0,-0x1            ; Уменьшаем счётчик
        and v1,v1,t0                ; Обрезаем старший байт
        or r6,r6,v1                 ; Объединяем с старшими байтами
        sw v0,0x4(t1)               ; Сохраняем счётчик
        jal storeColor
        sw r6,-0x31a8(r7)           ; Сохраняем обновлённую цепочку

; ===== ИНИЦИАЛИЗАЦИЯ ЦЕПОЧКИ КОПИРОВАНИЯ =====
        move r4,s5                  ; Адрес текущей цепочки
        sll r5,s0,0x10              ; Координата X
        sra r5,r5,0x10
        sll r6,s1,0x10              ; Координата Y
        jal initCopyCharChain        ; Инициализация цепочки копирования
        sra r6,r6,0x10

; ===== НАСТРОЙКА SCRATCH PAD ДЛЯ DMA =====
        lui r6,0x1f80  
        ori r6,r6,0x348             ; r6 = 1f800348 - начало данных символа в scratch

        ; ... (паттерны 4-bit и инициализация пропущены для краткости)

; ===== ОСНОВНОЙ ЦИКЛ ОБРАБОТКИ СИМВОЛОВ =====
NextChar:
        addiu r4,r4,-0x20           ; Сдвигаем непечатаемые символы

        ; ОБРАБОТКА ПРОБЕЛОВ
        bne r4,zero,SpaceCheckBranch
        nop

        lui t2,MyAddr
        lh v0,-0xE(t2)              ; Текущий счётчик символов
        nop
        lh t3,-0x10(t2)             ; Общий счётчик символов
        addiu v0,v0,1
        beq v0,t3,SpaceCheckBranch  ; Если последний символ - не обрабатываем пробел
        nop

        ; ПРОБЕЛ - только сдвигаем позицию
        sh v0,-0xE(t2)              ; Обновляем счётчик
        nop
        lbu r4,0x0(s4)              ; Следующий символ

        ; СДВИГ ПОЗИЦИИ X
        lhu v0,0xa8(gp)             ; Начальный X
        lhu v1,0x8(s3)              ; Текущий X в scratch
        addiu v0,v0,0x6             ; Сдвиг на 6 пикселей
        addu v1,v1,v0               ; Новый X
        sh v1,0x8(s3)               ; Обновляем в scratch DMA

        j NextChar
        addiu s4,s4,0x1             ; Следующий байт текста

; ===== ОБРАБОТКА НЕ-ПРОБЕЛЬНЫХ СИМВОЛОВ =====
SpaceCheckBranch:
        jal makeCharPixelsCustom    ; СОЗДАЁМ ПИКСЕЛИ СИМВОЛА В SCRATCH
        clear s2

; ===== ФОРМИРОВАНИЕ КОМАНДЫ КОПИРОВАНИЯ SPRITE =====
PageLoop:
        ; ЗАГРУЗКА ЦЕПОЧКИ КОПИРОВАНИЯ SPRITE
        lw v0,-0x3198(s6)           ; Адрес свободной цепочки копирования (8007ce68)
        nop
        and r4,v0,t2                ; Старшие байты
        and v0,v0,s0                ; Младшие байты
        or r5,v0,s1                 ; r5 = полный адрес цепочки (80xxxxxx)

        ; ОБНОВЛЕНИЕ СЧЁТЧИКА КОПИРОВАНИЯ
        lw v0,0x4(s7)               ; Счётчик команд копирования
        lw v1,0x0(r5)               ; Следующая свободная цепочка
        addiu v0,v0,-0x1            ; Уменьшаем счётчик
        and v1,v1,s0                ; Обрезаем старший байт
        or r4,r4,v1                 ; Объединяем
        sw v0,0x4(s7)               ; Сохраняем счётчик
        sw r4,-0x3198(s6)           ; Сохраняем обновлённую цепочку

; ===== КОПИРОВАНИЕ ИЗ SCRATCH В ЦЕПОЧКУ =====
CopyCmdFromScratch:
        ; Копируем команду DMA из scratch в цепочку
        lw t9,0x0(s3)               ; Количество команд (04000000)
        lw t7,0x4(s3)               ; Команда копирования спрайта (64808080)
        lw t8,0x8(s3)               ; Координаты XY на экране
        lw t5,0xc(s3)               ; CLUT и координаты текстуры

        ; СОХРАНЯЕМ В ЦЕПОЧКУ КОПИРОВАНИЯ
        sw t9,0x0(r5)               ; 
        sw t7,0x4(r5)
        sw t8,0x8(r5)
        sw t5,0xc(r5)
        lw t9,0x10(s3)              ; Размер спрайта после копирования
        nop
        sw t9,0x10(r5)              ; Последняя команда

; ===== СВЯЗЫВАНИЕ ЦЕПОЧЕК =====
        ; СВЯЗЬ: ЦЕПОЧКА ФОРМИРОВАНИЯ → ЦЕПОЧКА КОПИРОВАНИЯ
        lw v1,0x18(t1)              ; Текущая цепочка формирования
        lw v0,0x0(r5)               ; Текущая команда копирования
        lw v1,0x0(v1)               ; Следующая цепочка формирования
        and v0,v0,t2                ; Маска старших байтов
        and v1,v1,s0                ; Маска младших байтов
        or v0,v0,v1                 ; Объединяем
        sw v0,0x0(r5)               ; Обновляем команду

        ; ОБНОВЛЯЕМ ССЫЛКУ В ЦЕПОЧКЕ ФОРМИРОВАНИЯ
        lw r4,0x18(t1)              ; Адрес цепочки формирования
        nop
        lw v0,0x0(r4)               ; Текущая команда формирования
        and v1,r5,s0                ; Адрес цепочки копирования
        and v0,v0,t2                ; Маска старших байтов
        or v0,v0,v1                 ; Объединяем
        sw v0,0x0(r4)               ; Сохраняем обновлённую ссылку

        sw r5,0x18(t1)              ; Сохраняем текущую цепочку копирования

; ===== ПРОВЕРКА ПЕРВОГО СИМВОЛА =====
        lhu v0,0x4(t6)              ; Счётчик символов
        nop
        bne v0,zero,NotFirstChar    ; Если не первый символ - пропускаем
        nop

        ; ИНИЦИАЛИЗАЦИЯ ДЛЯ ПЕРВОГО СИМВОЛА
        sw r5,0x28(t1)              ; Устанавливаем первую цепочку символа
        sw t8,0xc(t6)               ; Сохраняем координаты в параметрах

NotFirstChar:

; ===== КОПИРОВАНИЕ ДАННЫХ СИМВОЛА ИЗ SCRATCH =====
        lui r5,0x1f80
        ori r5,r5,0x348             ; r5 = данные символа в scratch

        lw v0,-0x31a8(t3)           ; Следующая свободная цепочка формирования
        and r4,v0,t2                ; Старшие байты
        and v0,v0,s0                ; Младшие байты
        or r7,v0,s1                 ; r7 = адрес цепочки (80xxxxxx)
        move r6,r7                  ; r6 = адрес назначения

        ; ... (копирование данных пропущено для краткости)

; ===== СВЯЗЫВАНИЕ: ДАННЫЕ СИМВОЛА → КОМАНДА КОПИРОВАНИЯ =====
        lw v1,0x18(t1)              ; Текущая команда копирования
        lw v0,0x0(r7)               ; Текущие данные символа
        lw v1,0x0(v1)               ; Следующая команда копирования
        and v0,v0,t2                ; Маска старших байтов
        and v1,v1,s0                ; Маска младших байтов
        or v0,v0,v1                 ; Объединяем
        sw v0,0x0(r7)               ; Обновляем данные символа

        ; ОБНОВЛЯЕМ ССЫЛКУ В КОМАНДЕ КОПИРОВАНИЯ
        lw r4,0x18(t1)              ; Адрес команды копирования
        nop
        lw v0,0x0(r4)               ; Текущая команда
        and v1,r7,s0                ; Адрес данных символа
        and v0,v0,t2                ; Маска старших байтов
        or v0,v0,v1                 ; Объединяем
        sw v0,0x0(r4)               ; Сохраняем обновлённую ссылку

        sw r7,0x18(t1)              ; Сохраняем текущие данные символа

; ===== СДВИГ ПОЗИЦИИ ДЛЯ СЛЕДУЮЩЕГО СИМВОЛА =====
        lhu v0,0xa8(gp)             ; Начальный X
        lhu v1,0x8(s3)              ; Текущий X
        addiu v0,v0,0x6             ; Сдвиг на 6 пикселей
        addu v1,v1,v0               ; Новый X
        sh v1,0x8(s3)               ; Обновляем

; ===== ПРОВЕРКА ЗАВЕРШЕНИЯ ТЕКСТА =====
        lhu v0,0x4(s5)              ; Счётчик символов DMA
        lui t9,MyAddr
        addiu v0,v0,0x1
        sh v0,0x4(s5)               ; Сохраняем

        ; ПРОВЕРКА ПЕРЕПОЛНЕНИЯ DMA
        lw v0,0x4(s7)               ; Текущий счётчик
        move v1,5                   ; Минимальный лимит
        sltu v0,v0,v1               ; Проверяем переполнение
        bne v0,zero,TextEnd         ; Если переполнение - завершаем

        ; ПРОВЕРКА КОНЦА СТРОКИ
        lui t3,MyAddr
        lhu v0,-0xE(t3)             ; Текущий символ
        lhu v1,-0x10(t3)            ; Общее количество символов
        addiu v0,v0,0x1
        lbu r4,0x0(s4)              ; Следующий символ
        sh v0,-0xE(t3)              ; Сохраняем счётчик
        addiu s4,s4,0x1             ; Сдвигаем указатель

        bne v0,v1,NextChar          ; Если не конец - продолжаем
        nop

; ===== ЗАВЕРШЕНИЕ ОБРАБОТКИ ТЕКСТА =====
TextEnd:
        ; ... (восстановление контекста и завершение)