494 lines
28 KiB
NASM
494 lines
28 KiB
NASM
/////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Persona 2 Eternal Punishment (PSX) JAP / Custom Characters/Data Patch
|
||
// Author: Sergey Shemet 05/11/2025
|
||
//
|
||
// v 1.1 - Grouped Chars VRAM Rendering
|
||
//
|
||
|
||
.psx
|
||
|
||
// Определения функций
|
||
.definelabel SetDrawTPage, 0x800578fc
|
||
.definelabel storeColor, 0x8001c0b4
|
||
.definelabel initCopyCharChain, 0x8001b110
|
||
.definelabel MakeShadowSmallChar, 0x8001b2a8
|
||
.definelabel PrintBigDMAText, 0x8001a3a8
|
||
|
||
.definelabel MyAddr, 0x8009
|
||
|
||
.open "2_EP/BIN/SLPS_028.25", 0x8000F800
|
||
|
||
.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 ra, 0x48(sp) // Сохраняем регистры
|
||
sw s0, 0x28(sp)
|
||
sw s1, 0x2c(sp)
|
||
sw s2, 0x30(sp)
|
||
sw s3, 0x34(sp)
|
||
sw s4, 0x38(sp) // Сохраняем регистры
|
||
sw s5, 0x3c(sp)
|
||
sw s6, 0x40(sp)
|
||
sw s7, 0x44(sp)
|
||
|
||
sw s8, 0x24(sp)
|
||
|
||
move s6, a0 // Адрес чтения текста -> s6
|
||
move s1, a1
|
||
move s2, a2
|
||
|
||
|
||
// Смещаем поинтер чтения
|
||
andi v0, v0, 0xff // Берем младший байт
|
||
addiu s6, s6, 0x2 // Сдвигаем указатель текста на +2 байта
|
||
lui s3, MyAddr
|
||
sh v0, -0x10(s3) // Сохраняем счетчик байтов @ 8008fff0 для общего количества
|
||
sh v0, -0x0e(s3) // Сохраняем счетчик байтов @ 8008fff2 для обратного отсчёта
|
||
|
||
lui t0, 0xff
|
||
ori t0, t0, 0xffff // t0 = 00FFFFFF
|
||
|
||
sw s0, 0x28(sp) // Сохраняем s0 в стеке
|
||
andi s0, a3, 0xff // s0 - режим текста (цвет и тень)
|
||
move a0, s0 // a0 = s0 (обрезанный цвет)
|
||
lui a3, 0x8008 // a3 = 80080000
|
||
lui a2, 0xff00 // a2 = FF000000
|
||
|
||
//Начинаем формировать цепочки
|
||
addiu t1, a3, -0x31a8 // t1 = 8007ce68 - Второй счётчик цепочек (корорый меньше)
|
||
lw v1, 0x0(t1) // v1 = загружаем свободную цепочку
|
||
lbu a1, 0x60(sp) // Флаг тени из стека -> a1
|
||
lui v0, 0x8000 // v0 = 80000000
|
||
|
||
and a2, v1, a2 // a2 = v1 & ff000000
|
||
andi a1, a1, 0xff // Очищаем режим текста
|
||
and v1, v1, t0 // v1 & 00ffffff
|
||
or s4, v1, v0 // s5 - основной адрес свободной цепочки
|
||
lw v0, 0x4(t1) // Загружаем счетчик DMA
|
||
lw v1, 0x0(s4) // v1 = следующий свободный адрес в цепочке
|
||
addiu v0, v0, -0x1 // Уменьшаем счетчик DMA
|
||
and v1, v1, t0 // v1 & 00ffffff
|
||
or a2, a2, v1 // a2 | v1 = следующая свободная цепочка
|
||
sw v0, 0x4(t1) // Сохраняем счетчик DMA
|
||
jal storeColor //Сохраняем цвет
|
||
sw a2, 0x0(t1) // Сохраняем следующую свободную цепочку
|
||
|
||
move a0, s4 // Текущий адрес цепочки как параметр инициализации (a0)
|
||
sll a1, s1, 0x10 // a1 = X << 16
|
||
sra a1, a1, 0x10 // a1 = X координата
|
||
sll a2, s2, 0x10 // a2 = Y << 16
|
||
sra a2, a2, 0x10 // a2 = Y координата
|
||
jal initCopyCharChain // Инициализация цепочки символов (в a0 адрес, a1 - X, a2 - Y)
|
||
move a3, s0 //Режим
|
||
|
||
cputovram_scratchpad_template:
|
||
// Инициализация ScratchPad (CPU to VRAM)
|
||
lui a3, 0x1f80
|
||
ori a3, a3, 0x0348 // a3 = CpuToVram cmd template addr
|
||
|
||
lui a1, 0x0F00 // Количество команд без flushcache
|
||
sw a1, 0x0(a3) // Сохраняем количество команд
|
||
|
||
lui a0, 0xa000 // a0 = a0000000
|
||
sw a0, 0x4(a3)
|
||
|
||
lui v0, 0x01f0
|
||
ori v0, 0x0130
|
||
sw v0, 0x8(a3) // сохраняем VU для CPUtoVRAM
|
||
|
||
lui v0, 0xc
|
||
ori v0, 0x2
|
||
sw v0, 0xc(a3) // сохраняем 000c0002 (ширина в 16-битных пикселях)
|
||
|
||
_1bppTo4bpp_table_template:
|
||
// Копирование таблицы преобразования 1bpp в 4bpp
|
||
lui t8, 0x1f80
|
||
ori t8, t8, 0x390
|
||
lui t7, 0x8001
|
||
ori t7, t7, 0x5fc
|
||
lw t5, 0x0(t7)
|
||
lw t6, 0x4(t7)
|
||
sw t5, 0x0(t8)
|
||
sw t6, 0x4(t8)
|
||
lw t5, 0x8(t7)
|
||
lw t6, 0xC(t7)
|
||
sw t5, 0x8(t8)
|
||
sw t6, 0xC(t8)
|
||
lw t5, 0x10(t7)
|
||
lw t6, 0x14(t7)
|
||
sw t5, 0x10(t8)
|
||
sw t6, 0x14(t8)
|
||
lw t5, 0x18(t7)
|
||
lw t6, 0x1C(t7)
|
||
sw t5, 0x18(t8)
|
||
sw t6, 0x1C(t8)
|
||
|
||
rect_scratchpad_template:
|
||
// Шаблон команды rect в scratchpad
|
||
lui s3, 0x1f80
|
||
ori s3, 0x03d0 // s3 = 1f8003d0 - адрес rect в scratchpad
|
||
lui v0, 0x0400
|
||
sw v0, 0x0(s3) // Длина цепочки = 4
|
||
lui v0, 0x6480
|
||
ori v0, 0x8080
|
||
sw v0, 0x4(s3)
|
||
li v0, 0xf0c0
|
||
sh v0, 0xc(s3) // Сохраняем координаты VU (всегда f0c0)
|
||
lhu v1, 0xa0(gp) // Загружаем CLUT из GP (всегда 7FD3)
|
||
|
||
li v0, 0
|
||
sw v0, 0x8(s3) //Чистим экранные координаты
|
||
sh s2, 0xa(s3) //И сразу устанавливаем Y
|
||
|
||
lui v0, 0xc
|
||
ori v0, 0x8 // Ширина спрайта = 8
|
||
sw v0, 0x10(s3) // Сохраняем ширину
|
||
sh v1, 0xe(s3) // Сохраняем CLUT
|
||
|
||
make_sprite_size_table:
|
||
lui s3, 0x1f80
|
||
ori s3, 0x03f0 // Будем серить в scratch
|
||
lui v0, 0x0403 // таблицей рассчитанных команд и ширин
|
||
ori v0, 0x0201 // необходимых для спрайтов линии (cmdCount << 2)
|
||
sw v0, 0x0(s3)
|
||
lui v1, 0x0706
|
||
ori v1, 0x0504
|
||
sw v1, 0x4(s3)
|
||
li v0, 0x0807
|
||
sh v0, 0x8(s3)
|
||
|
||
misc_init:
|
||
move t6, s1 // Текущий экранный X, который будет смещаться и писаться в команду rect
|
||
// Устанавливаем, исходя из прилетевшей координаты X
|
||
|
||
TextGroupReadLoop:
|
||
// Смотрим количество символов до предела (не более 10) (проверяем MyAddr-0xE)
|
||
// Отнимаем количество символов в MyAddr-0xE. Устанавливаем признак, если ещё не конец
|
||
// Копируем символы во временный буфер MyAddr (-0x0с)
|
||
|
||
lui s3, 0x1f80
|
||
ori s3, 0x03f0 // Перезадаём адрес таблицы количества спрайтов для нового цикла
|
||
lui t1, MyAddr //Постоянный счётчик
|
||
|
||
lh v1, -0x0e(t1) //Загружаем количество оставшихся символов
|
||
lui t2, MyAddr //Сдвиг для буфера
|
||
sltiu a0, v1, 0x0B //Меньше 10 в строке?
|
||
bne a0, zero, readTextToBuffer
|
||
clear s2 //Обнуляем счётчик символов
|
||
li v1, 0xA //Установка максимального количество символов
|
||
|
||
readTextToBuffer:
|
||
lbu a0, 0x0(s6) // Основное чтение байта текста
|
||
addiu s6, s6, 0x1 // Сдвиг адреса чтения на +1 байт
|
||
addiu v1, v1, -0x1 // Осталось в этом блоке...
|
||
sb a0, -0x0c(t2) // Запись символа в буфер
|
||
addiu s2, s2, 0x1 // Счётчик прочитанного +1
|
||
lh v0, -0x0e(t1) // Грузим общий счётчик
|
||
addiu t2, t2, 0x1 // Сдвиг записи +1
|
||
addiu v0, v0, -0x01 // Общий счётчик -1
|
||
bne v1, zero, readTextToBuffer // Проверяем частный счётчик != 0
|
||
sh v0, -0x0e(t1) // Сохраняем общий счётчик
|
||
|
||
li a0, 0
|
||
sb a0, -0x0c(t2) //На всякий случай сохраняем 00-терминатор
|
||
|
||
addu s3, s3, s2 // получаем адрес количества спрайтов из таблицы
|
||
addiu s3, -0x1 // index -1
|
||
lbu a1, 0x0(s3) // Читаем количество в a1
|
||
nop
|
||
move t5, a1 // Храним количество блоков для спрайта
|
||
|
||
lui t3, 0x1f80
|
||
ori t3, t3, 0x1c0 // Начало данных спрайта в scratch
|
||
|
||
form_char_data_in_scratch:
|
||
jal make_char_line_in_scratch //Вызываем процедуру формирования строки
|
||
move a0, s2 //Передаём в неё длину строки в символах (a0) и в спрайтах (a1)
|
||
// (формируем спрайт размером до 60x12)
|
||
|
||
rect_cmd_init:
|
||
|
||
lui s3, 0x1f80
|
||
ori s3, 0x03d0 // s3 = 1f8003d0 - адрес rect в scratchpad
|
||
|
||
lui s1, 0x8008 // Загружаем 80080000
|
||
|
||
lui s0, 0xff
|
||
ori s0, s0, 0xffff // s0 = 00ffffff
|
||
lui s7, 0x8000 // s7 = 80000000
|
||
|
||
lui t2, 0xff00 // t2 = ff000000
|
||
move t4, s4 // t4 - указатель на print params ОСНОВНОЙ
|
||
move t1, s4 // t1 - print params для смещения страниц
|
||
|
||
rect_set_X:
|
||
sh t6, 0x8(s3) // Сохраняем X координату в текущий rect
|
||
|
||
sll v0, s2, 1
|
||
addu v0, s2 // Умножаем количество обработанных символов на 6
|
||
sll v0, 1
|
||
addu t6, v0 // Сдвигаем X (прочитаем со следующим блоком символов)
|
||
rect_set_width:
|
||
sll v0, t5, 3 //Количество блоков спрайта * 8 = ширина спрайта
|
||
sh v0, 0x10(s3) // Сохраняем ширину спрайта
|
||
|
||
PageLoop:
|
||
|
||
////// Балансировщик нагрузки выбора цепочек для равномерного размещения команд (2 команды в 7ce58 + 1 команда в 7ce68)
|
||
//////////////////////////////////////// TODO: CHAIN BALANCER
|
||
addiu s5, s1, -0x3198 // s5 = 7ce68 (Второй свободный адрес dma)
|
||
|
||
//s5 - содержит указатель на адрес следующей свободной цепочки. В зависимости от балансировщика может быть 7ce58 или 7ce68
|
||
|
||
// Создание цепочки копирования спрайта
|
||
lw v0, 0x0(s5) // v0 = *адрес свободной цепочки
|
||
nop
|
||
and a0, v0, t2 // a0 = v0 & ff00..
|
||
and v0, v0, s0 // v0 & 00FFFFFF
|
||
or a1, v0, s7 // a1 = v0 | s7 (80000000)
|
||
lw v0, 0x4(s5) // Счетчик команд
|
||
lw v1, 0x0(a1) // Новый адрес свободной цепочки
|
||
addiu v0, v0, -0x1 // Уменьшаем счетчик
|
||
and v1, v1, s0 // v1 & 00FFFFFF
|
||
or a0, a0, v1 // a0 & v1
|
||
sw v0, 0x4(s5) // Сохраняем счетчик DMA
|
||
sw a0, 0x0(s5) // Сохраняем новую свободную цепочку
|
||
|
||
rect_copy_scratch_to_ram:
|
||
lw t8, 0x0(s3) // Количество команд DMA
|
||
lw t7, 0x4(s3) // Команда копирования спрайта
|
||
sw t8, 0x0(a1)
|
||
sw t7, 0x4(a1)
|
||
lw a3, 0x8(s3) // Координаты экрана XY
|
||
lw t7, 0xc(s3) // CLUT и координаты текстуры
|
||
sw a3, 0x8(a1)
|
||
sw t7, 0xc(a1)
|
||
lw t8, 0x10(s3) // Размер спрайта после копирования
|
||
nop
|
||
sw t8, 0x10(a1) // Сохраняем последнюю команду
|
||
|
||
|
||
rect_scratch_connect:
|
||
lw v1, 0x18(t1) // Загружаем адрес след цепочки из print params (cur page)
|
||
lw v0, 0x0(a1) // Текущий новый адрес цепочки
|
||
lw v1, 0x0(v1) // Разыменование
|
||
and v0, v0, t2 // v0 & ff000000
|
||
and v1, v1, s0 // v1 & 00FFFFFF
|
||
or v0, v0, v1 // Команды с FFFFFF
|
||
sw v0, 0x0(a1) // Обновляем текущий адрес цепочки
|
||
|
||
lw a0, 0x18(t1) // Загружаем адрес след цепочки из print params (cur page)
|
||
nop
|
||
lw v0, 0x0(a0) // Разыменование
|
||
and v1, a1, s0 // v1 = a1 & 00FFFFFF
|
||
and v0, v0, t2 // v0 & FF000000 - чистим кол-во команд
|
||
or v0, v0, v1 // прикручиваем кол-во команд к след адресу
|
||
sw v0, 0x0(a0) // Сохраняем в цепочку ссылку
|
||
sw a1, 0x18(t1) // Сохраняем адрес след актуальной цепочки в print params (cur page)
|
||
|
||
lhu v0, 0x4(t4) // Проверяем счетчик символов в print params
|
||
nop
|
||
bne v0, zero, cpu2vram_cmd_loop // Если счетчик символов ≠ 0, переходим (уже инициализировали)
|
||
clear s8 // Сбрасываем счётчик команд спрайтов
|
||
|
||
sw a1, 0x28(t1) // Устанавливаем адрес начала цепочки символов в print_params (для хранения значения "цепочка от адреса...")
|
||
sw a3, 0xc(t4) // Сохраняем экранные координаты в print params
|
||
|
||
|
||
cpu2vram_cmd_loop:
|
||
// Цикл команд cpu_to_vram (формирование спрайтов текста в VRAM)
|
||
|
||
////// Балансировщик нагрузки выбора цепочек для равномерного размещения команд (2 команды в 7ce58 + 1 команда в 7ce68)
|
||
//////////////////////////////////////// TODO: CHAIN BALANCER
|
||
addiu s5, s1, -0x31a8 // s5 = 7ce58 (Первый свободный адрес dma)
|
||
|
||
//s5 - содержит указатель на адрес следующей свободной цепочки. В зависимости от балансировщика может быть 7ce58 или 7ce68
|
||
|
||
lw v0, 0x0(s5) // Следующая свободная цепочка 7ce58 ()
|
||
nop
|
||
and a0, v0, t2 // a0 = v0 & FF000000
|
||
and v0, v0, s0 // v0 & 00FFFFFF
|
||
or a3, v0, s7 // a3 = следующая цепочка & 80...
|
||
move a2, a3 // a2 = a3 (следующая цепочка)
|
||
lw v0, 0x4(s5) // Счетчик команд
|
||
lw v1, 0x0(a3) // Новый адрес свободной цепочки
|
||
addiu v0, v0, -0x1 // Уменьшаем счетчик
|
||
and v1, v1, s0 // v1 & 00FFFFFF
|
||
or a0, a0, v1 // a0 & v1
|
||
sw v0, 0x4(s5) // Сохраняем счетчик DMA
|
||
sw a0, 0x0(s5) // Сохраняем новую свободную цепочку
|
||
|
||
//Копируем шаблон cpu2vram
|
||
|
||
lui a1, 0x1f80
|
||
ori a1, a1, 0x348 // 1f800348 = Scratch команда cpu2vram
|
||
lw t8, 0x0(a1)
|
||
lw t7, 0x4(a1)
|
||
sw t8, 0x0(a2)
|
||
sw t7, 0x4(a2)
|
||
lw t8, 0x8(a1) //Сохраняем базу команды cpu2vram
|
||
lw t7, 0xc(a1)
|
||
sw t8, 0x8(a2)
|
||
sw t7, 0xc(a2)
|
||
|
||
sll v1, s8, 1 //Текущий индекс блока * 2
|
||
addiu v0, v1, 0x130 //складываем со 0x130 (X начала спрайта в VRAM)
|
||
sh v0, 0x8(a2) //Обновляем VU X прямо в RAM
|
||
|
||
copy_char_data_start:
|
||
lui t3, 0x1f80
|
||
ori t3, t3, 0x1c0 // Начало данных спрайта в scratch
|
||
|
||
addiu a2, 0x10 //Адрес для записи данных после заголовка команды
|
||
clear v0 //Основной счётчик строк (0-11)
|
||
|
||
sll v1, t5, 2 //v1 = количество байт в одной строке (блоки * 4) (инкремент)
|
||
sll a1, s8, 2 //Вычисляем смещение начала чтения
|
||
addu a1, t3 //a1 = адрес начала чтения в scratch
|
||
|
||
copy_char_data_loop:
|
||
lw t7, 0x0(a1) //Грузим данные
|
||
addu a1, v1 //Смещаем адрес чтения
|
||
sw t7, 0x0(a2) //Сохраняем данные
|
||
|
||
addiu a2, 0x04 //Смещаем адрес записи
|
||
addiu v0, 0x01 //Инкремент счётчика строк
|
||
bne v0, 0x0c, copy_char_data_loop
|
||
nop
|
||
|
||
bne s8, zero, cpu2vram_dma_link // Если это первая команда (последняя выполняемая, то добавляем flushcache)
|
||
nop
|
||
|
||
set_flush_cache_cmd:
|
||
li t8, 0x10
|
||
sb t8, -0x3d(a2) //Обновляем длину команды до 0x10
|
||
lui t8, 0x0100
|
||
sw t8, 0x0(a2) //Устанавливаем команду flush cache в конце команды
|
||
|
||
cpu2vram_dma_link:
|
||
// Связывание предыдущей команды с текущей (формирование ссылки в заголовке команды)
|
||
lw v1, 0x18(t1) // v1 <- 18+(t1) - указатель на конец цепочки в текущей странице)
|
||
lw v0, 0x0(a3) // v0 <- 0+(a3) - снова читаем первую команду (в данном случае - количество команд)
|
||
lw v1, 0x0(v1) // Разыменование указателя на след свободный адрес в цепочке (из print_params)
|
||
and v0, v0, t2 // v0 & FF..... Чистим количество команд
|
||
and v1, v1, s0 // v1 & 00FFFFFF - чистим след свободный адрес
|
||
or v0, v0, v1 // Совмещаем ссылку - Cmd+ADDR
|
||
sw v0, 0x0(a3) // Сохраняем ссылку в цепочку
|
||
|
||
//Связывание текущей команды со следующей (формирование ссылки в заголовке команды + запись в print params)
|
||
lw a0, 0x18(t1) // v1 <- 18+(t1) - указатель на конец цепочки в текущей странице)
|
||
nop
|
||
lw v0, 0x0(a0) // Читаем то, на что указывает указатель (след адрес в цепочке из цепочки)
|
||
and v1, a3, s0 // v1 = a3 & 00FFFFFF - от следующего адреса свободной команды отрезаем 80
|
||
and v0, v0, t2 // v0 & FF000000 (количество команд) от след адреса
|
||
or v0, v0, v1 // Совмещаем ссылку - Cmd+ADDR
|
||
sw v0, 0x0(a0) // Сохраняем ссылку в цепочку
|
||
sw a3, 0x18(t1) // Сохраняем адрес последней команды в print params
|
||
|
||
//Конец цикла команд cpu_to_vram
|
||
addiu s8, 0x1 //Смешаем индекс читаемого спрайта
|
||
bne s8, t5, cpu2vram_cmd_loop //Проверка на достижение количества спрайтов
|
||
nop
|
||
|
||
addiu t1, t1, 0x4 // Сдвигаем print params для следующей страницы
|
||
addiu v0, t4, 0x8 // v0 = t4 + 8 (t1 не должен быть больше, чем t4 + 4)
|
||
sltu v0, t1, v0 // Проверяем прохождение первой страницы
|
||
bne v0, zero, PageLoop // Если не прошли, продолжаем цикл страниц
|
||
nop
|
||
|
||
chunk_making_end:
|
||
// Увеличиваем счетчик символов + проверка
|
||
lhu v0, 0x4(s4) // Текущее количество спрайтов
|
||
lui t3, MyAddr
|
||
addiu v0, v0, 0x1 // Увеличиваем на 1
|
||
lhu v1, -0x0e(t3) // Количество оставшихся символов
|
||
sh v0, 0x4(s4) // Сохраняем счетчик спрайтов в print_params
|
||
|
||
bne v1, zero, TextGroupReadLoop
|
||
// Если обработаны все буквы и созданы все спрайты, то выходим
|
||
nop
|
||
|
||
|
||
TextEnd:
|
||
clear s2
|
||
lui s3, 0x8008
|
||
addiu s5, s3, -0x3198 // s5 = 7ce68 (Второй свободный адрес dma)
|
||
lui s1, 0xff
|
||
ori s1, s1, 0xffff // s1 = 00ffffff
|
||
move s0, s4 // s0 = Указатель на print params (теперь они и в t1, s4 и s0)
|
||
clear a1
|
||
|
||
PageTLoop:
|
||
//Добавляем команду переключения текстурной страницы (SetDrawTPage) в обе страницы
|
||
li a2, 0x1 // a2 = 1
|
||
addu s2, s2, a2 // Увеличиваем счетчик страниц
|
||
|
||
lui v0, 0x8000 // v0 = 80000000
|
||
lui a0, 0xff00 // a0 = ff000000
|
||
|
||
lw v1, 0x0(s5) // Следующая свободная цепочка
|
||
lw a3, 0x9c(gp) // Текстурная страница из параметров
|
||
and v1, v1, s1 // v1 & 00FFFFFF
|
||
or v1, v1, v0 // v1 | v0 = 80.....
|
||
sw v1, 0x30(s0) // Сохраняем последний адрес в print params
|
||
|
||
//Линкуем адреса
|
||
lw v0, 0x0(s5) // Следующая свободная цепочка ещё раз!
|
||
lw v1, 0x0(v1) // разыменование
|
||
and v0, v0, a0 // v0 & ff000000
|
||
and v1, v1, s1 // v1 & 00FFFFFF
|
||
lw a0, 0x4(s5) // Счетчик DMA
|
||
or v0, v0, v1 // v0 | v1
|
||
sw v0, 0x0(s5) // Сохраняем свободный адрес
|
||
addiu a0, -0x1 // Уменьшаем счетчик DMA
|
||
sw a0, 0x4(s5) // Сохраняем счетчик DMA
|
||
lw a0, 0x30(s0) // Читаем адрес команды в a0 для передачи в функцию установки texPage
|
||
jal SetDrawTPage // Устанавливаем страницу отрисовки
|
||
addiu s0, s0, 0x4 // Смещаем print params для следующей страницы
|
||
sltiu v0, s2, 0x2 // Проверяем счетчик < 2
|
||
bne v0, zero, PageTLoop // Если да, продолжаем цикл
|
||
clear a1 // a1 = 0
|
||
|
||
move v0, s4 // Возвращаем основные параметры DMA
|
||
|
||
// Восстанавливаем регистры из стека
|
||
lw ra, 0x48(sp)
|
||
|
||
|
||
lw s7, 0x44(sp)
|
||
lw s6, 0x40(sp)
|
||
lw s5, 0x3c(sp)
|
||
lw s4, 0x38(sp)
|
||
lw s3, 0x34(sp)
|
||
lw s2, 0x30(sp)
|
||
lw s1, 0x2c(sp)
|
||
lw s0, 0x28(sp)
|
||
|
||
lw s8, 0x24(sp) //need to be saved!
|
||
|
||
jr ra // Возврат
|
||
addiu sp, sp, 0x50 // Восстанавливаем стек
|
||
|
||
|
||
.include "2_EP/EP_charload_grouped.asm"
|
||
.include "2_EP/EP_charCalcs.asm"
|
||
.close
|
||
|
||
.include "2_EP/EP_txtpatches.asm" // misc text patches
|
||
|
||
|
||
|
||
|
||
// compile with ./armips -sym 2_EP/BUILD_LOGS/SLPS_028.25.map -temp 2_EP/BUILD_LOGS/SLPS_028.25.txt 2_EP/EP_main_grouped.asm |