Files
Persona2-PSX-asm-sources/IS_main_grouped.asm
2025-10-18 17:25:22 +05:00

485 lines
27 KiB
NASM
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; Persona 2 Innocent Sin (PSX) JAP / Custom Characters/Data Patch
; Author: Sergey Shemet 12/10/2021
.psx
// Определения функций
.definelabel SetDrawTPage, 0x800542cc
.definelabel storeColor, 0x8001b0c8
.definelabel initCopyCharChain, 0x8001a070
.definelabel makeCharPixels, 0x8001a08f // need custom routine with custom font
.definelabel GenerateSmallChar, 0x8001a284 // need custom routine
.definelabel MakeShadowSmallChar, 0x8001a20c
.definelabel PrintBigDMAText, 0x80019300
.definelabel MyAddr, 0x8009
.open "SLPS_021.00", 0x8000F800
.include "complex_strings_copy.asm"
.org 0x80090000
ExternalPrint:
// Текстовая тестовая процедура
move v1, s3 // Сохраняем s3
move s3, a0 // Устанавливаем s3 как адрес текста
lhu v0, 0x0(s3) // Читаем 2 байта текста
move s3, v1 // Восстанавливаем s3
srl v1, v0, 0xD // Проверяем 13-й бит (система 1 байт)
bne v1, zero, MyPrintLineRoutine // Если установлен, переходим к нашей процедуре
clear v1
j PrintBigDMAText // Иначе используем стандартную процедуру
nop
MyPrintLineRoutine:
addiu sp, sp, -0x50 // Выделяем место в стеке
sw ra, 0x4c(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 s8, 0x48(sp)
sw s7, 0x44(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, -0x4930 // t1 = 8007b6d0 - новая свободная цепочка
lw v1, -0x4930(a3) // v1 = загружаем свободную цепочку
lbu a1, 0x60(sp) // Флаг тени из стека -> a1
lui v0, 0x8000 // v0 = 80000000
// Инициализация цвета и textParams
and a2, v1, a2 // a2 = v1 & ff000000
andi a1, a1, 0xff // Очищаем режим текста
and v1, v1, t0 // v1 & 00ffffff
or s4, v1, v0 // s4 - основной адрес свободной цепочки
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, -0x4930(a3) // Сохраняем следующую свободную цепочку
move a0, s4 // Текущий адрес цепочки
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 // Инициализация цепочек символов
move a3, s0 // Сохраняем режим текста
// Шаблон cpuToVram
cputovram_scratchpad_template:
lui a3, 0x1f80
ori a3, a3, 0x0348 // a3 = первый символ начала
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
_1bppTo4bpp_table_template:
// Копирование таблицы преобразования 1bpp в 4bpp
lui t8, 0x1f80
ori t8, t8, 0x390
lui t7, 0x8001
ori t7, t7, 0x3e8
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, 0xa8(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 //Постоянный счётчик
//TODO!!!!!: Динамическая длина строки для соединения с переменными!
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
addiu s5, s1, -0x4930 // s5 = 7b6d0 (временный DMA)
lui s0, 0xff
ori s0, s0, 0xffff // s0 = 00ffffff
lui s7, 0x8000 // s7 = 80000000
//Старый неактуальный код из далёкого атлусовского прошлого
// Инициализация координат XY
//lw v0, 0xb0(gp) // Какой-то множитель ширины символа. В нашем случае не нужен!
//lhu v1, 0x4(s4) // Старый счётчик символов сейчас считает спрайты
// addiu v0, v0, 0x6 // 0x06 * 6px между буквами!
// mult v1, v0 // v1 * v0 = смещение X * номер символа
// addiu t3, sp, 0x10 // t3 = sp + 10
// sh s8, 0xa(s3) // экранный Y установлен на этапе формироания rect
lui t2, 0xff00 // t2 = ff000000
move t4, s4 // t4 - указатель на print params ОСНОВНОЙ
move t1, s4 // t1 - print params для смещения страниц
rect_set_X:
// lhu t5, 0x20(sp) // Загружаем X из стека
// mflo t6 // Результат умножения
// addu v0, t5, t6 // v0 = 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:
// Создание цепочки копирования спрайта
lw v0, -0x4930(s1) // 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, -0x4930(s1) // Сохраняем новую свободную цепочку
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) // Следующий параметр
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) // Первый адрес цепочки
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) // Текущий адрес цепочки
lhu v0, 0x4(t4) // Счетчик символов
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
lw v0, -0x4930(s1) // Следующая свободная цепочка
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, -0x4930(s1) // Сохраняем новую свободную цепочку
//Тут "оптимизировали" копирование в short, и сделали своё копирование со смещением спрайтов
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 (начало блока спрайта в 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 = начинаем с него
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:
// Связывание DMA символа + копирование спрайта
lw v1, 0x18(t1) // Текущая цепочка DMA копирования спрайта
lw v0, 0x0(a3) // Текущие команды цепочки символов
lw v1, 0x0(v1) // Количество команд + следующая ссылка
and v0, v0, t2 // v0 & FF.....
and v1, v1, s0 // v1 & 00FFFFFF
or v0, v0, v1 // Количество команд & FF..
sw v0, 0x0(a3) // Сохраняем текущую команду цепочки
lw a0, 0x18(t1) // Адрес заголовка текущей команды копирования спрайта
nop
lw v0, 0x0(a0) // 04FFFFFF
and v1, a3, s0 // v1 = копирование текущей цепочки символов
and v0, v0, t2 // v0 & FF000000 (количество команд)
or v0, v0, v1 // Полная команда со ссылкой
sw v0, 0x0(a0) // Сохраняем с ссылкой на цепочку символов
sw a3, 0x18(t1) // Последняя цепочка символов
//Конец цикла команд cpu_to_vram
addiu s8, 0x1
bne s8, t5, cpu2vram_cmd_loop
nop
addiu t1, t1, 0x4 // Сдвигаем параметры для следующей страницы
addiu v0, t4, 0x8 // Сдвигаем первый параметр цепочки для страницы
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, -0x4930 // s5 = 7b6d0
lui s1, 0xff
ori s1, s1, 0xffff // s1 = 00ffffff
move s0, s4 // s0 = текущие параметры строки
clear a1
PageTLoop:
// Завершающая обработка страниц
li a2, 0x1 // a2 = 1
addu s2, s2, a2 // Увеличиваем счетчик
lui v0, 0x8000 // v0 = 80000000
lui a0, 0xff00 // a0 = ff000000
lw v1, -0x4930(s3) // Следующая свободная цепочка
lw a3, 0xa4(gp) // Некоторые параметры (почти DMA)
and v1, v1, s1 // v1 & 00FFFFFF
or v1, v1, v0 // v1 | v0 = 80.....
sw v1, 0x30(s0) // Сохраняем последний свободный адрес в параметрах DMA
lw v0, -0x4930(s3) // Следующая свободная цепочка
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, -0x4930(s3) // Новый адрес свободной цепочки
addiu a0, a0, -0x1 // Уменьшаем счетчик DMA
sw a0, 0x4(s5) // Сохраняем счетчик DMA
lw a0, 0x30(s0) // Начало цепочки DMA
jal SetDrawTPage // Устанавливаем страницу отрисовки
addiu s0, s0, 0x4 // Сдвигаем параметры DMA для следующей страницы
sltiu v0, s2, 0x2 // Проверяем счетчик < 2
bne v0, zero, PageTLoop // Если да, продолжаем цикл
clear a1 // a1 = 0
move v0, s4 // Возвращаем основные параметры DMA
// Восстанавливаем регистры из стека
lw ra, 0x4c(sp)
lw s8, 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)
jr ra // Возврат
addiu sp, sp, 0x50 // Восстанавливаем стек
.ascii "This game was officially cracked by SERGEY SHEMET 2021-2025. WHAT ARE YOU DOING HERE, BOY?"
.byte 0x00
.byte 0x00
// Включаем дополнительные файлы
.include "IS_charload_grouped.asm"
.include "IS_battle_GG_name_render.asm"
.include "charCalcs.asm"
.close
.include "txtpatches.asm" // misc text patches
// compile with ./armips -sym SLPS_021.00.map -temp 123.txt is_main_grouped.asm