Files
Persona2-PSX-asm-sources/2_EP/EP_main_grouped.asm
2025-11-04 23:06:09 +05:00

410 lines
21 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 Eternal Punishment (PSX) JAP / Custom Characters/Data Patch
; Author: Sergey Shemet 06/10/2022
.psx
// Определения функций
.definelabel SetDrawTPage, 0x800578fc
.definelabel storeColor, 0x8001c0b4
.definelabel initCopyCharChain, 0x8001b110
.definelabel MakeShadowSmallChar, 0x8001b2a8
.definelabel PrintBigDMAText, 0x8001a3a8
.definelabel MyAddr, 0x8009
.open "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 s4, 0x38(sp) // Сохраняем регистры
move s4, a0 // Адрес чтения текста -> s4
sw s0, 0x28(sp)
move s0, a1
sw s1, 0x2c(sp)
move s1, a2
sw s3, 0x34(sp)
// Обработка новой команды
andi v0, v0, 0xff // Берем младший байт
addiu s4, s4, 0x2 // Сдвигаем указатель текста на +2 байта
lui s3, MyAddr
sw v0, -0x10(s3) // Сохраняем счетчик байтов @ 8008fff0
// Инициализация scratchpad
lui s3, 0x1f80
ori s3, s3, 0x3d0 // s3 = 1f8003d0 - команда копирования спрайта
lui t0, 0xff
ori t0, t0, 0xffff // t0 = 00FFFFFF
andi a0, a3, 0xff // Режим текста (цвет и тень)
lui a3, 0x8008 // a3 = 80080000
lui a2, 0xff00 // a2 = FF000000
addiu t1, a3, -0x31a8 // t1 = 8007b6d0 - новая свободная цепочка
lw v1, -0x31a8(a3) // v1 = загружаем свободную цепочку
lbu a1, 0x60(sp) // Флаг тени из стека -> a1
lui v0, 0x8000 // v0 = 80000000
sw ra, 0x48(sp) // Сохраняем регистры
sw s7, 0x44(sp)
sw s6, 0x40(sp)
sw s5, 0x3c(sp)
sw s2, 0x30(sp)
// Инициализация цепочек
and a2, v1, a2 // a2 = v1 & ff000000
andi a1, a1, 0xff // Очищаем режим текста
and v1, v1, t0 // v1 & 00ffffff
or s5, v1, v0 // s5 - основной адрес свободной цепочки
lw v0, 0x4(t1) // Загружаем счетчик DMA
lw v1, 0x0(s5) // v1 = следующая свободная цепочка
addiu v0, v0, -0x1 // Уменьшаем счетчик DMA
and v1, v1, t0 // v1 & 00ffffff
or a2, a2, v1 // a2 | v1 = следующая свободная цепочка
sw v0, 0x4(t1) // Сохраняем счетчик DMA
sw a2, -0x31a8(a3) // Сохраняем следующую свободную цепочку
jal storeColor
move a0, s5 // Текущий адрес цепочки
sll a1, s0, 0x10 // a1 = X << 16
sra a1, a1, 0x10 // a1 = X координата
sll a2, s1, 0x10 // a2 = Y << 16
jal initCopyCharChain // Инициализация цепочек символов
sra a2, a2, 0x10 // a2 = Y координата
// Инициализация ScratchPad (CPU to VRAM)
lui a2, 0x1f80
ori a2, a2, 0x348 // a2 = первый символ начала
// 4-битная таблица паттернов
.include "EP_4bitPattern.asm"
li v0, 0x2
sh v0, 0x1c(sp)
li v0, 0xc
li a0, 0x10 // Команды в цепочке формирования символа?
lui v1, 0xa000 // a0 = a0000000
sh v0, 0x1e(sp) // Сохраняем 000C0002 в стек+1c
// Инициализация символа
lui v0, 0x100 // Сброс кэша 01000000
sb a0, 0x3(a2) // Сохраняем количество команд
sw v1, 0x4(a2) // Сохраняем a0000000
lui at, 0x1f80 // Начало scratchpad
sw v0, 0x388(at) // Сохраняем в конец первой цепочки символов
// Формирование команды DMA копирования спрайта
li v0, 0x4
sb v0, 0x3(s3) // Длина цепочки = 4
li v0, 0x64
sb v0, 0x7(s3) // Команда копирования спрайта
lhu a0, 0x98(gp) // Загружаем X координату
lhu v1, 0x9a(gp) // Загружаем Y координату
li v0, 0x80
sb v0, 0x4(s3)
sb v0, 0x5(s3)
sb v0, 0x6(s3) // Формируем 80808064
setY1:
lw v0, 0x1c(sp) // v0 = 000c0002 из стека
lh a3, 0x98(gp) // Для дальнейших расчетов X спрайта
sh a0, 0x18(sp)
sh v1, 0x1a(sp) // Сохраняем координаты в стек
lw a0, 0x18(sp) // Загружаем координаты из стека
move t0, a3
sw a0, 0x8(a2) // Загружаем координаты в DMA
sw v0, 0xc(a2) // Сохраняем в первый символ
bgez a3, LAB_800194fc
SetX1:
sh s1, 0x20(sp) // Сохраняем X половину в sp+20
addiu t0, a3, 0x3f
LAB_800194fc:
// Декодирование координат для исходного спрайта
sra v0, t0, 0x6 // v0 = t0 >> 6
sll v0, v0, 0x6 // v0 << 6
subu v0, a3, v0 // v0 = a3 - v0
lh v1, 0x9a(gp) // Загружаем Y половину из памяти
sll v0, v0, 0x2 // v0 << 2
sb v0, 0xc(s3) // Сохраняем X байт спрайта символа
bgez v1, LAB_80019520 // Если Y >= 0 - ветвление
move v0, v1
addiu v0, v1, 0xff // Иначе v0 = ff - v1
LAB_80019520:
sra v0, v0, 0x8
sll v0, v0, 0x8
subu v0, v1, v0
sb v0, 0xd(s3) // Сохраняем Y байт спрайта символа
lhu v1, 0xa0(gp)
li v0, 0x8 // Ширина спрайта = 8
sh v0, 0x10(s3) // Сохраняем ширину
sh v1, 0xe(s3) // Сохраняем значение
sh s0, 0x8(s3) // Сохраняем X
sh s1, 0xa(s3) // Сохраняем Y
li v0, 0xc // Высота спрайта = 12
sh v0, 0x12(s3) // Сохраняем высоту
// Начало чтения текста
lbu a0, 0x0(s4) // Основное чтение байта команды
nop
addiu s4, s4, 0x1 // Сдвиг адреса чтения на +1 байт
SpaceCheckBranch:
jal makeCharPixelsCustom // Создание маленького символа в scratch
clear s2
lui t2, 0xff00 // t2 = ff000000
move t6, s5 // Параметры
addiu t5, sp, 0x10 // t5 = sp + 10
lui t3, 0x8008
addiu t4, t3, -0x31a8
move t1, s5 // Параметры снова
SetY:
SetX:
PageLoop:
// Создание цепочки копирования спрайта
lw v0, -0x3198(s6) // v0 = *адрес свободной цепочки
nop
and a0, v0, t2 // a0 = v0 & ff00..
and v0, v0, s0 // v0 & 00FFFFFF
or a1, v0, s1 // a1 = v0 | 80000000
lw v0, 0x4(s7) // Счетчик команд
lw v1, 0x0(a1) // Новый адрес свободной цепочки
addiu v0, v0, -0x1 // Уменьшаем счетчик
and v1, v1, s0 // v1 & 00FFFFFF
or a0, a0, v1 // a0 & v1
sw v0, 0x4(s7) // Сохраняем счетчик DMA
sw a0, -0x3198(s6) // Сохраняем новую свободную цепочку
CopyCmdFromScratch:
// Копирование команды из scratch
lw t9, 0x0(s3) // Количество команд DMA
lw t7, 0x4(s3) // Команда копирования спрайта
lw t8, 0x8(s3) // Координаты экрана XY
lw t5, 0xc(s3) // CLUT и координаты текстуры
sw t9, 0x0(a1)
sw t7, 0x4(a1)
sw t8, 0x8(a1)
sw t5, 0xc(a1)
lw t9, 0x10(s3) // Размер спрайта после копирования
nop
sw t9, 0x10(a1) // Сохраняем последнюю команду
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(t6) // Счетчик символов
nop
bne v0, zero, NotFirstChar // Если счетчик символов 0, переходим
nop
sw a1, 0x28(t1) // Устанавливаем первую цепочку символов
sw t8, 0xc(t6) // Сохраняем координаты в параметры
// sh s2, 0xe(t4) // Сохраняем половину Y
NotFirstChar:
lui a1, 0x1f80 // Адрес символа здесь
lw v0, -0x31a8(t3) // Следующая свободная цепочка
ori a1, a1, 0x348 // a1 | 1f800348 = Scratch данные символа
and a0, v0, t2 // a0 = v0 & FF000000
and v0, v0, s0 // v0 & 00FFFFFF
or a3, v0, s1 // a3 = следующая цепочка & 80...
move a2, a3 // a2 = a3 (следующая цепочка)
lw v0, 0x4(t4) // Счетчик команд
lw v1, 0x0(a3) // Новый адрес свободной цепочки
addiu v0, v0, -0x1 // Уменьшаем счетчик
and v1, v1, s0 // v1 & 80... количество команд
or a0, a0, v1 // a0 & v1
sw v0, 0x4(t4) // Сохраняем счетчик DMA
andi v0, a3, 0x3 // Проверяем адрес назначения MOD 4
sw a0, -0x31a8(t3) // Сохраняем новую свободную цепочку
beq v0, zero, Copy16Bytes // Если MOD 4 = 0, ветвление
addiu v0, a1, 0x40
CopyBy2Bytes:
// Копируем по 2 байта если MOD 4 0
lwl t9, 0x3(a1)
lwr t9, 0x0(a1)
lwl t7, 0x7(a1)
lwr t7, 0x4(a1)
lwl t8, 0xb(a1)
lwr t8, 0x8(a1)
lwl t5, 0xf(a1)
lwr t5, 0xc(a1)
swl t9, 0x3(a2)
swr t9, 0x0(a2)
swl t7, 0x7(a2)
swr t7, 0x4(a2)
swl t8, 0xb(a2)
swr t8, 0x8(a2)
swl t5, 0xf(a2)
swr t5, 0xc(a2)
addiu a1, a1, 0x10
bne a1, v0, CopyBy2Bytes
addiu a2, a2, 0x10
j last4BytesCopy
nop
Copy16Bytes:
// Копируем по 16 байт
lw t9, 0x0(a1)
lw t7, 0x4(a1)
lw t8, 0x8(a1)
lw t5, 0xc(a1)
sw t9, 0x0(a2)
sw t7, 0x4(a2)
sw t8, 0x8(a2)
sw t5, 0xc(a2)
addiu a1, a1, 0x10
bne a1, v0, Copy16Bytes
addiu a2, a2, 0x10
last4BytesCopy:
// Копируем последние 4 байта
lwl t9, 0x3(a1)
lwr t9, 0x0(a1)
nop
swl t9, 0x3(a2)
swr t9, 0x0(a2)
// Связывание 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) // Последняя цепочка символов
addiu t1, t1, 0x4 // Сдвигаем параметры для следующей страницы
addiu v0, t6, 0x8 // Сдвигаем первый параметр цепочки для страницы
sltu v0, t1, v0 // Проверяем прохождение первой страницы
bne v0, zero, PageLoop // Если не прошли, продолжаем цикл страниц
nop
// Сдвиг X координаты (+6)
lhu v0, 0xa8(gp) // Загружаем начальный X
lhu v1, 0x8(s3) // Загружаем последний X в scratch
addiu v0, v0, 0x6 // v0 = начальный X + 6
addu v1, v1, v0 // Последний X = последний X + (начальный X + 6)
sh v1, 0x8(s3) // Обновляем последний X в DMA scratch
SpaceJump:
// Увеличиваем счетчик символов + проверка
lhu v0, 0x4(s5) // Текущее количество символов DMA
lui t9, MyAddr
addiu v0, v0, 0x1 // Увеличиваем на 1
sh v0, 0x4(s5) // Сохраняем счетчик в цепочку
// Проверка переполнения DMA
lw v0, 0x4(s7) // Счетчик команд DMA
move v1, 5 // Минимальный счетчик команд
sltu v0, v0, v1 // v0 < v1?
bne v0, zero, TextEnd // Если переполнение DMA, завершаем текст
nop
lui t3, MyAddr
lhu v0, -0xE(t3) // Количество символов в строке
lhu v1, -0x10(t3) // Общее количество символов в строке
addiu v0, v0, 0x1 // Увеличиваем на 1
lbu a0, 0x0(s4) // Загружаем следующий символ
sh v0, -0xE(t3) // Сохраняем счетчик символов
addiu s4, s4, 0x1 // Сдвигаем адрес символа
bne v0, v1, NextChar // Если текущий символ общему количеству, продолжаем
nop
TextEnd:
clear s2
lui s3, 0x8008
addiu s4, s3, -0x3198 // s4 = 7b6d0
lui s1, 0xff
ori s1, s1, 0xffff // s1 = 00ffffff
move s0, s5 // 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, -0x3198(s3) // Следующая свободная цепочка
lw a3, 0x9c(gp) // Некоторые параметры (почти DMA)
and v1, v1, s1 // v1 & 00FFFFFF
or v1, v1, v0 // v1 | v0 = 80.....
sw v1, 0x30(s0) // Сохраняем последний свободный адрес в параметрах DMA
lw v0, -0x3198(s3) // Следующая свободная цепочка
lw v1, 0x0(v1) // Создаем еще одну цепочку
and v0, v0, a0 // v0 & ff000000
and v1, v1, s1 // v1 & 00FFFFFF
lw a0, 0x4(s4) // Счетчик DMA
or v0, v0, v1 // v0 | v1
sw v0, -0x3198(s3) // Новый адрес свободной цепочки
addiu a0, a0, -0x1 // Уменьшаем счетчик DMA
sw a0, 0x4(s4) // Сохраняем счетчик 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, s5 // Возвращаем основные параметры 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)
jr ra // Возврат
addiu sp, sp, 0x50 // Восстанавливаем стек