EP: Groped chars v1.1
+ char calcs calls
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
;
|
||||
; Persona 2 Eternal Punishment (PSX) JAP / Custom Characters/Data Patch
|
||||
; Author: Sergey Shemet 06/10/2022
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Persona 2 Eternal Punishment (PSX) JAP / Custom Characters/Data Patch
|
||||
// Author: Sergey Shemet 05/11/2025
|
||||
//
|
||||
// v 1.1 - Grouped Chars VRAM Rendering
|
||||
//
|
||||
|
||||
.psx
|
||||
|
||||
@@ -13,12 +17,12 @@
|
||||
|
||||
.definelabel MyAddr, 0x8009
|
||||
|
||||
.open "SLPS_028.25", 0x8000F800
|
||||
.open "2_EP/BIN/SLPS_028.25", 0x8000F800
|
||||
|
||||
.org 0x80090000
|
||||
|
||||
ExternalPrint:
|
||||
// Текстовая тестовая процедура
|
||||
|
||||
lhu v0, 0x0(a0) // Читаем 2 байта текста
|
||||
nop
|
||||
srl v1, v0, 0xD // Проверяем 13-й бит (система 1 байт)
|
||||
@@ -29,366 +33,428 @@ ExternalPrint:
|
||||
|
||||
MyPrintLineRoutine:
|
||||
addiu sp, sp, -0x50 // Выделяем место в стеке
|
||||
sw s4, 0x38(sp) // Сохраняем регистры
|
||||
move s4, a0 // Адрес чтения текста -> s4
|
||||
sw ra, 0x48(sp) // Сохраняем регистры
|
||||
sw s0, 0x28(sp)
|
||||
move s0, a1
|
||||
sw s1, 0x2c(sp)
|
||||
move s1, a2
|
||||
sw s2, 0x30(sp)
|
||||
sw s3, 0x34(sp)
|
||||
sw s4, 0x38(sp) // Сохраняем регистры
|
||||
sw s5, 0x3c(sp)
|
||||
sw s6, 0x40(sp)
|
||||
sw s7, 0x44(sp)
|
||||
|
||||
// Обработка новой команды
|
||||
move s6, a0 // Адрес чтения текста -> s6
|
||||
move s1, a1
|
||||
move s2, a2
|
||||
|
||||
|
||||
// Смещаем поинтер чтения
|
||||
andi v0, v0, 0xff // Берем младший байт
|
||||
addiu s4, s4, 0x2 // Сдвигаем указатель текста на +2 байта
|
||||
|
||||
addiu s6, s6, 0x2 // Сдвигаем указатель текста на +2 байта
|
||||
lui s3, MyAddr
|
||||
sw v0, -0x10(s3) // Сохраняем счетчик байтов @ 8008fff0
|
||||
sh v0, -0x10(s3) // Сохраняем счетчик байтов @ 8008fff0 для общего количества
|
||||
sh v0, -0x0e(s3) // Сохраняем счетчик байтов @ 8008fff2 для обратного отсчёта
|
||||
|
||||
// Инициализация 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
|
||||
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 = 8007b6d0 - новая свободная цепочка
|
||||
lw v1, -0x31a8(a3) // v1 = загружаем свободную цепочку
|
||||
//Начинаем формировать цепочки
|
||||
addiu t1, a3, -0x31a8 // t1 = 8007ce68 - Второй счётчик цепочек (корорый меньше)
|
||||
lw v1, 0x0(t1) // 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)
|
||||
lui v0, 0x8000 // v0 = 80000000
|
||||
|
||||
// Инициализация цепочек
|
||||
and a2, v1, a2 // a2 = v1 & ff000000
|
||||
and a2, v1, a2 // a2 = v1 & ff000000
|
||||
andi a1, a1, 0xff // Очищаем режим текста
|
||||
and v1, v1, t0 // v1 & 00ffffff
|
||||
or s5, v1, v0 // s5 - основной адрес свободной цепочки
|
||||
and v1, v1, t0 // v1 & 00ffffff
|
||||
or s4, 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 = следующая свободная цепочка
|
||||
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
|
||||
jal storeColor //Сохраняем цвет
|
||||
sw a2, 0x0(t1) // Сохраняем следующую свободную цепочку
|
||||
|
||||
move a0, s4 // Текущий адрес цепочки
|
||||
sll a1, s1, 0x10 // a1 = X << 16
|
||||
sra a1, a1, 0x10 // a1 = X координата
|
||||
sll a2, s1, 0x10 // a2 = Y << 16
|
||||
jal initCopyCharChain // Инициализация цепочек символов
|
||||
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 a2, 0x1f80
|
||||
ori a2, a2, 0x348 // a2 = первый символ начала
|
||||
lui a3, 0x1f80
|
||||
ori a3, a3, 0x0348 // a3 = CpuToVram cmd template addr
|
||||
|
||||
// 4-битная таблица паттернов
|
||||
.include "EP_4bitPattern.asm"
|
||||
lui a1, 0x0F00 // Количество команд без flushcache
|
||||
sw a1, 0x0(a3) // Сохраняем количество команд
|
||||
|
||||
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 a0, 0xa000 // a0 = a0000000
|
||||
sw a0, 0x4(a3)
|
||||
|
||||
// Инициализация символа
|
||||
lui v0, 0x100 // Сброс кэша 01000000
|
||||
sb a0, 0x3(a2) // Сохраняем количество команд
|
||||
sw v1, 0x4(a2) // Сохраняем a0000000
|
||||
lui v0, 0x01f0
|
||||
ori v0, 0x0130
|
||||
sw v0, 0x8(a3) // сохраняем VU для CPUtoVRAM
|
||||
|
||||
lui at, 0x1f80 // Начало scratchpad
|
||||
sw v0, 0x388(at) // Сохраняем в конец первой цепочки символов
|
||||
lui v0, 0xc
|
||||
ori v0, 0x2
|
||||
sw v0, 0xc(a3) // сохраняем 000c0002 (ширина в 16-битных пикселях)
|
||||
|
||||
// Формирование команды DMA копирования спрайта
|
||||
li v0, 0x4
|
||||
sb v0, 0x3(s3) // Длина цепочки = 4
|
||||
li v0, 0x64
|
||||
sb v0, 0x7(s3) // Команда копирования спрайта
|
||||
_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)
|
||||
|
||||
lhu a0, 0x98(gp) // Загружаем X координату
|
||||
lhu v1, 0x9a(gp) // Загружаем Y координату
|
||||
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, 0x9a(gp) // Загружаем CLUT из GP (всегда 7FD3)
|
||||
|
||||
li v0, 0
|
||||
sw v0, 0x8(s3) //Чистим экранные координаты
|
||||
sh s2, 0xa(s3) //И сразу устанавливаем Y
|
||||
|
||||
li v0, 0x80
|
||||
sb v0, 0x4(s3)
|
||||
sb v0, 0x5(s3)
|
||||
sb v0, 0x6(s3) // Формируем 80808064
|
||||
lui v0, 0xc
|
||||
ori v0, 0x8 // Ширина спрайта = 8
|
||||
sw v0, 0x10(s3) // Сохраняем ширину
|
||||
sh v1, 0xe(s3) // Сохраняем CLUT
|
||||
|
||||
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) // Сохраняем в первый символ
|
||||
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)
|
||||
|
||||
bgez a3, LAB_800194fc
|
||||
misc_init:
|
||||
move t6, s1 // Текущий экранный X, который будет смещаться и писаться в команду rect
|
||||
// Устанавливаем, исходя из прилетевшей координаты X
|
||||
|
||||
SetX1:
|
||||
sh s1, 0x20(sp) // Сохраняем X половину в sp+20
|
||||
addiu t0, a3, 0x3f
|
||||
TextGroupReadLoop:
|
||||
// Смотрим количество символов до предела (не более 10) (проверяем MyAddr-0xE)
|
||||
// Отнимаем количество символов в MyAddr-0xE. Устанавливаем признак, если ещё не конец
|
||||
// Копируем символы во временный буфер MyAddr (-0x0с)
|
||||
|
||||
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
|
||||
lui s3, 0x1f80
|
||||
ori s3, 0x03f0 // Перезадаём адрес таблицы количества спрайтов для нового цикла
|
||||
lui t1, MyAddr //Постоянный счётчик
|
||||
|
||||
LAB_80019520:
|
||||
sra v0, v0, 0x8
|
||||
sll v0, v0, 0x8
|
||||
subu v0, v1, v0
|
||||
sb v0, 0xd(s3) // Сохраняем Y байт спрайта символа
|
||||
lhu v1, 0xa0(gp)
|
||||
lh v1, -0x0e(t1) //Загружаем количество оставшихся символов
|
||||
lui t2, MyAddr //Сдвиг для буфера
|
||||
sltiu a0, v1, 0x0B //Меньше 10 в строке?
|
||||
bne a0, zero, readTextToBuffer
|
||||
clear s2 //Обнуляем счётчик символов
|
||||
li v1, 0xA //Установка максимального количество символов
|
||||
|
||||
li v0, 0x8 // Ширина спрайта = 8
|
||||
sh v0, 0x10(s3) // Сохраняем ширину
|
||||
sh v1, 0xe(s3) // Сохраняем значение
|
||||
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-терминатор
|
||||
|
||||
sh s0, 0x8(s3) // Сохраняем X
|
||||
sh s1, 0xa(s3) // Сохраняем Y
|
||||
addu s3, s3, s2 // получаем адрес количества спрайтов из таблицы
|
||||
addiu s3, -0x1 // index -1
|
||||
lbu a1, 0x0(s3) // Читаем количество в a1
|
||||
nop
|
||||
move t5, a1 // Храним количество блоков для спрайта
|
||||
|
||||
li v0, 0xc // Высота спрайта = 12
|
||||
sh v0, 0x12(s3) // Сохраняем высоту
|
||||
lui t3, 0x1f80
|
||||
ori t3, t3, 0x1c0 // Начало данных спрайта в scratch
|
||||
|
||||
// Начало чтения текста
|
||||
lbu a0, 0x0(s4) // Основное чтение байта команды
|
||||
nop
|
||||
addiu s4, s4, 0x1 // Сдвиг адреса чтения на +1 байт
|
||||
form_char_data_in_scratch:
|
||||
jal make_char_line_in_scratch //Вызываем процедуру формирования строки
|
||||
move a0, s2 //Передаём в неё длину строки в символах (a0) и в спрайтах (a1)
|
||||
// (формируем спрайт размером до 60x12)
|
||||
|
||||
SpaceCheckBranch:
|
||||
jal makeCharPixelsCustom // Создание маленького символа в scratch
|
||||
clear s2
|
||||
rect_cmd_init:
|
||||
|
||||
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 // Параметры снова
|
||||
lui s3, 0x1f80
|
||||
ori s3, 0x03d0 // s3 = 1f8003d0 - адрес rect в scratchpad
|
||||
|
||||
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) // Сохраняем новую свободную цепочку
|
||||
lui s1, 0x8008 // Загружаем 80080000
|
||||
|
||||
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) // Сохраняем последнюю команду
|
||||
lui s0, 0xff
|
||||
ori s0, s0, 0xffff // s0 = 00ffffff
|
||||
lui s7, 0x8000 // s7 = 80000000
|
||||
|
||||
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
|
||||
lui t2, 0xff00 // t2 = ff000000
|
||||
move t4, s4 // t4 - указатель на print params ОСНОВНОЙ
|
||||
move t1, s4 // t1 - print params для смещения страниц
|
||||
|
||||
sw a1, 0x28(t1) // Устанавливаем первую цепочку символов
|
||||
sw t8, 0xc(t6) // Сохраняем координаты в параметры
|
||||
// sh s2, 0xe(t4) // Сохраняем половину Y
|
||||
rect_set_X:
|
||||
sh t6, 0x8(s3) // Сохраняем X координату в текущий rect
|
||||
|
||||
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) // Сохраняем новую свободную цепочку
|
||||
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) // Сохраняем ширину спрайта
|
||||
|
||||
beq v0, zero, Copy16Bytes // Если MOD 4 = 0, ветвление
|
||||
addiu v0, a1, 0x40
|
||||
PageLoop:
|
||||
|
||||
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
|
||||
////// Балансировщик нагрузки выбора цепочек для равномерного размещения команд (2 команды в 7ce58 + 1 команда в 7ce68)
|
||||
//////////////////////////////////////// TODO: CHAIN BALANCER
|
||||
addiu s5, s1, -0x3198 // s5 = 7ce68 (Второй свободный адрес dma)
|
||||
|
||||
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
|
||||
//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) // Сохраняем новую свободную цепочку
|
||||
|
||||
last4BytesCopy:
|
||||
// Копируем последние 4 байта
|
||||
lwl t9, 0x3(a1)
|
||||
lwr t9, 0x0(a1)
|
||||
nop
|
||||
swl t9, 0x3(a2)
|
||||
swr t9, 0x0(a2)
|
||||
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) // Сохраняем последнюю команду
|
||||
|
||||
// Связывание 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
|
||||
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) // Обновляем текущий адрес цепочки
|
||||
|
||||
// Сдвиг 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
|
||||
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 // Сбрасываем счётчик команд спрайтов
|
||||
|
||||
SpaceJump:
|
||||
// Увеличиваем счетчик символов + проверка
|
||||
lhu v0, 0x4(s5) // Текущее количество символов DMA
|
||||
lui t9, MyAddr
|
||||
addiu v0, v0, 0x1 // Увеличиваем на 1
|
||||
sh v0, 0x4(s5) // Сохраняем счетчик в цепочку
|
||||
sw a1, 0x28(t1) // Устанавливаем адрес начала цепочки символов в print_params (для хранения значения "цепочка от адреса...")
|
||||
sw a3, 0xc(t4) // Сохраняем экранные координаты в print params
|
||||
|
||||
// Проверка переполнения 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 // Сдвигаем адрес символа
|
||||
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
|
||||
|
||||
bne v0, v1, NextChar // Если текущий символ ≠ общему количеству, продолжаем
|
||||
nop
|
||||
|
||||
TextEnd:
|
||||
clear s2
|
||||
lui s3, 0x8008
|
||||
addiu s4, s3, -0x3198 // s4 = 7b6d0
|
||||
addiu s5, s3, -0x3198 // s5 = 7ce68 (Второй свободный адрес dma)
|
||||
lui s1, 0xff
|
||||
ori s1, s1, 0xffff // s1 = 00ffffff
|
||||
move s0, s5 // s0 = текущие параметры строки
|
||||
move s0, s4 // s0 = Указатель на print params (теперь они и в t1, s4 и s0)
|
||||
clear a1
|
||||
|
||||
PageTLoop:
|
||||
// Завершающая обработка страниц
|
||||
//Добавляем команду переключения текстурной страницы (SetDrawTPage) в обе страницы
|
||||
li a2, 0x1 // a2 = 1
|
||||
addu s2, s2, a2 // Увеличиваем счетчик
|
||||
addu s2, s2, a2 // Увеличиваем счетчик страниц
|
||||
|
||||
lui v0, 0x8000 // v0 = 80000000
|
||||
lui a0, 0xff00 // a0 = ff000000
|
||||
lw v1, -0x3198(s3) // Следующая свободная цепочка
|
||||
lw a3, 0x9c(gp) // Некоторые параметры (почти DMA)
|
||||
|
||||
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) // Сохраняем последний свободный адрес в параметрах DMA
|
||||
lw v0, -0x3198(s3) // Следующая свободная цепочка
|
||||
lw v1, 0x0(v1) // Создаем еще одну цепочку
|
||||
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(s4) // Счетчик DMA
|
||||
lw a0, 0x4(s5) // Счетчик 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
|
||||
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 // Сдвигаем параметры DMA для следующей страницы
|
||||
addiu s0, s0, 0x4 // Смещаем print params для следующей страницы
|
||||
sltiu v0, s2, 0x2 // Проверяем счетчик < 2
|
||||
bne v0, zero, PageTLoop // Если да, продолжаем цикл
|
||||
clear a1 // a1 = 0
|
||||
@@ -407,4 +473,16 @@ PageTLoop:
|
||||
lw s0, 0x28(sp)
|
||||
|
||||
jr ra // Возврат
|
||||
addiu sp, sp, 0x50 // Восстанавливаем стек
|
||||
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
|
||||
Reference in New Issue
Block a user