From 587e98f8bbd6c1d278676b1310bfbdb56a10be2f Mon Sep 17 00:00:00 2001 From: sShemet Date: Fri, 18 Apr 2025 22:50:54 +0500 Subject: [PATCH] vault backup: 2025-04-18 22:50:54 --- .../PSX code - modules load and exec.md | 255 +++++++++--------- 1 file changed, 121 insertions(+), 134 deletions(-) diff --git a/PERSONAL PROJECTS/PSX code - modules load and exec.md b/PERSONAL PROJECTS/PSX code - modules load and exec.md index 4cdc414..0bbf5ec 100644 --- a/PERSONAL PROJECTS/PSX code - modules load and exec.md +++ b/PERSONAL PROJECTS/PSX code - modules load and exec.md @@ -1,206 +1,193 @@ -Вот реализация вашей задачи для **PlayStation 1**, состоящая из трёх частей: -1. **Основная программа** (MAIN.C) - загружает и запускает дополнительные модули. -2. **Модуль 1** (MODULE1.C) - выводит сообщение и изменяет общую переменную. -3. **Модуль 2** (MODULE2.C) - читает ту же переменную и выводит изменённое значение. - -Все модули загружаются в **один адрес RAM (0x80030000)** и используют общие переменные через специальный заголовок. +Вот доработанная версия с **общими переменными между основной программой и модулями**. Мы создадим единую структуру `GameState`, которая будет передаваться в каждый модуль. --- -### **1. Структура проекта** -``` -project/ -├── MAIN.C (Основная программа) -├── MODULE1.C (Модуль 1) -├── MODULE2.C (Модуль 2) -├── SHARED.H (Общие определения) -└── SYSTEM.CNF -``` - ---- - -### **2. Общий заголовок (SHARED.H)** +### **1. Общий заголовок (SHARED.H)** ```c -// Структура для общих переменных +// Структура для общих переменных игры typedef struct { - int counter; - char message[32]; -} SharedData; + int lives; // Количество жизней + int level; // Текущий уровень + bool is_paused; // Состояние паузы + uint32_t score; // Счёт игрока +} GameState; -// Заголовок модуля (должен быть одинаковым во всех модулях) -typedef void (*ModuleFunc)(SharedData*); +// Заголовок модуля +typedef void (*ModuleEntry)(GameState*); // Тип функции-входа typedef struct { - uint32_t magic; // Магическое число 0x55AA1234 - ModuleFunc entry_point; // Точка входа - uint32_t size; // Размер модуля + uint32_t magic; // 0x55AA1234 + ModuleEntry entry; // Функция входа + uint32_t size; // Размер модуля } ModuleHeader; ``` --- -### **3. Основная программа (MAIN.C)** +### **2. Основная программа (MAIN.C)** ```c -#include #include -#include #include #include "SHARED.H" -#define MODULE_LOAD_ADDR 0x80030000 // Фиксированный адрес загрузки -#define MODULE1_SECTOR 1000 // Сектор начала MODULE1.BIN -#define MODULE1_SIZE 50 // Размер MODULE1.BIN в секторах -#define MODULE2_SECTOR 1100 // Сектор начала MODULE2.BIN -#define MODULE2_SIZE 50 // Размер MODULE2.BIN в секторах +#define MODULE_ADDR 0x80030000 // Адрес загрузки модулей -SharedData shared_data; // Общие данные +GameState game_state = { + .lives = 3, + .level = 1, + .is_paused = false, + .score = 0 +}; void load_and_run_module(int sector, int size) { - // 1. Загрузка модуля в фиксированный адрес - CdRead(sector, (uint32_t*)MODULE_LOAD_ADDR, size); + CdRead(sector, (uint32_t*)MODULE_ADDR, size); CdReadSync(0); - // 2. Проверка заголовка - ModuleHeader *header = (ModuleHeader*)MODULE_LOAD_ADDR; - if (header->magic != 0x55AA1234) { - FntPrint("Invalid module!\n"); - return; + ModuleHeader *header = (ModuleHeader*)MODULE_ADDR; + if (header->magic == 0x55AA1234) { + header->entry(&game_state); // Передаём указатель на game_state } - - // 3. Вызов точки входа модуля - header->entry_point(&shared_data); } int main() { ResetGraph(0); - InitPad(NULL, 0, NULL, 0); CdInit(); - SetVideoMode(MODE_NTSC); FntLoad(960, 256); FntOpen(16, 16, 256, 224, 0, 512); - // Инициализация общих данных - shared_data.counter = 0; - sprintf(shared_data.message, "Initial message"); - - // Загрузка и выполнение модулей по очереди while (1) { - FntPrint("Main program running...\n"); - - // Загрузить и выполнить MODULE1 - FntPrint("Loading MODULE1...\n"); - load_and_run_module(MODULE1_SECTOR, MODULE1_SIZE); - VSync(0); + // Обновляем общие переменные + game_state.score += 10; + FntPrint("Main: Lives=%d, Score=%d\n", game_state.lives, game_state.score); - // Загрузить и выполнить MODULE2 - FntPrint("Loading MODULE2...\n"); - load_and_run_module(MODULE2_SECTOR, MODULE2_SIZE); - VSync(0); + // Загружаем и выполняем модули + load_and_run_module(MODULE_MDEC_SECTOR, MODULE_MDEC_SIZE); + load_and_run_module(MODULE_GPU_SECTOR, MODULE_GPU_SIZE); - FntFlush(-1); VSync(0); } - - return 0; } ``` --- -### **4. Модуль 1 (MODULE1.C)** +### **3. Модуль для MDEC (MODULE_MDEC.C)** ```c +#include #include "SHARED.H" -void module_entry(SharedData *shared) { - // Изменяем общие данные - shared->counter++; - sprintf(shared->message, "MODULE1 was here!"); +void module_entry(GameState *state) { + // Читаем и изменяем общие переменные + if (state->lives > 0) { + state->lives--; // Уменьшаем жизни + FntPrint("MDEC: Lives left=%d\n", state->lives); + } - // Выводим сообщение (в реальности используйте FntPrint из основной программы) - // Здесь просто пример доступа к данным + // Декодируем видео только если игра не на паузе + if (!state->is_paused) { + uint8_t data[1024]; + uint16_t buffer[256*256]; + MDEC_DecodeFrame(data, buffer, MDEC_MODE_RGB24); + } } -// Важно: заголовок должен быть в конце файла! + ModuleHeader __header__ __attribute__((section(".header"))) = { .magic = 0x55AA1234, - .entry_point = module_entry, - .size = 0 // Заполнит компоновщик -}; -``` - ---- - -### **5. Модуль 2 (MODULE2.C)** -```c -#include "SHARED.H" - -void module_entry(SharedData *shared) { - // Читаем изменённые данные - shared->counter += 10; - sprintf(shared->message + 8, " + MODULE2!"); - - // Выводим сообщение -} -ModuleHeader __header__ __attribute__((section(".header"))) = { - .magic = 0x55AA1234, - .entry_point = module_entry, + .entry = module_entry, .size = 0 }; ``` --- -### **6. Компиляция и запись на диск** -1. Скомпилируйте каждый модуль **отдельно**: - ```bash - ccpsx MAIN.C -o MAIN.EXE - ccpsx MODULE1.C -o MODULE1.BIN - ccpsx MODULE2.C -o MODULE2.BIN - ``` +### **4. Модуль для GPU (MODULE_GPU.C)** +```c +#include +#include "SHARED.H" -2. Запишите на диск, указав **точные сектора**: - ``` - MAIN.EXE -> Сектор 0 - MODULE1.BIN -> Сектор 1000 (как указано в MAIN.C) - MODULE2.BIN -> Сектор 1100 - ``` +void module_entry(GameState *state) { + // Проверяем глобальный статус + if (state->is_paused) { + FntPrint("GPU: Game is paused!\n"); + return; + } -3. В `SYSTEM.CNF` укажите: - ``` - BOOT = cdrom:\MAIN.EXE;1 - ``` + // Рисуем HUD с общими переменными + char hud_text[32]; + sprintf(hud_text, "LIVES: %d SCORE: %d", state->lives, state->score); + FntPrint(hud_text); + + // Пример работы с GPU + RECT rect = {10, 10, 100, 100}; + uint16_t color = state->lives > 1 ? 0xFF00 : 0xFF0000; // Красный если 1 жизнь + DrawPrim(&rect); +} + +ModuleHeader __header__ __attribute__((section(".header"))) = { + .magic = 0x55AA1234, + .entry = module_entry, + .size = 0 +}; +``` --- -### **7. Как это работает** +### **5. Сборка** +```bash +# Компиляция модулей с их библиотеками +ccpsx MODULE_MDEC.C -o MODULE_MDEC.BIN -lpsxmdec +ccpsx MODULE_GPU.C -o MODULE_GPU.BIN -lpsxgpu + +# Основная программа (без лишних библиотек) +ccpsx MAIN.C -o MAIN.EXE +``` + +--- + +### **6. Механика общих переменных** 1. **Основная программа**: - - Загружает модули в `0x80030000` через `CdRead()`. - - Проверяет магическое число в заголовке. - - Вызывает `entry_point`, передавая указатель на общие данные. + - Создаёт глобальную структуру `GameState`. + - Передаёт **указатель** на неё в модули через `header->entry(&game_state)`. 2. **Модули**: - - Компилируются с **заголовком** в начале. - - Имеют доступ к `SharedData` через переданный указатель. - - Разрешены **только операции с данными** (нельзя использовать PsyQ напрямую). + - Читают и изменяют `GameState` через полученный указатель. + - Могут проверять: + ```c + if (state->is_paused) { ... } + ``` + - Могут изменять: + ```c + state->lives--; + ``` -3. **Общие переменные**: - - Расположены в основной программе. - - Модули получают к ним доступ через указатель. +3. **Синхронизация**: + - Все изменения мгновенно видны в основном модуле и других модулях. --- -### **8. Ограничения безопасности** -- Все модули **должны доверять** друг другу. -- Нет защиты от **переполнения буфера** (адрес загрузки фиксирован). -- Модули не должны **переопределять системные вызовы**. +### **7. Пример работы** +1. Основная программа: + - Устанавливает `lives = 3`, `score = 0`. +2. Модуль MDEC: + - Уменьшает `lives` до 2, если игрок ошибся. +3. Модуль GPU: + - Отображает текущие `lives` и `score` на экране. +4. Основная программа: + - Видит изменения и может реагировать (например, завершить игру при `lives == 0`). --- -### **9. Оптимизации** -- Используйте **DMA** для ускорения загрузки. -- Добавьте **CRC-проверку** модулей в заголовке. -- Для сложных модулей применяйте **релокацию** (но это сложнее). +### **8. Важные нюансы** +- **Безопасность**: Модули могут **перезаписать любые данные** в `GameState`. Добавьте проверки: + ```c + if (state->lives < 0) state->lives = 0; // Защита от отрицательных значений + ``` +- **Производительность**: Частый доступ к общим переменным может замедлить работу. Оптимизируйте: + ```c + int local_lives = state->lives; // Кэширование в локальную переменную + ``` +- **Конфликты**: Если модули работают с одними данными, добавьте **флаги блокировки**. -Этот подход используется в таких играх, как **Metal Gear Solid** (для загрузки скриптовых модулей). - -________________ +--- +Теперь модули могут **полноценно взаимодействовать** с основной программой, проверяя и изменяя глобальное состояние игры! 🎮 \ No newline at end of file