Files
SergObsidian/PERSONAL PROJECTS/PSX code - modules load and exec.md
2025-04-18 22:40:53 +05:00

207 lines
6.9 KiB
Markdown
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.

Вот реализация вашей задачи для **PlayStation 1**, состоящая из трёх частей:
1. **Основная программа** (MAIN.C) - загружает и запускает дополнительные модули.
2. **Модуль 1** (MODULE1.C) - выводит сообщение и изменяет общую переменную.
3. **Модуль 2** (MODULE2.C) - читает ту же переменную и выводит изменённое значение.
Все модули загружаются в **один адрес RAM (0x80030000)** и используют общие переменные через специальный заголовок.
---
### **1. Структура проекта**
```
project/
├── MAIN.C (Основная программа)
├── MODULE1.C (Модуль 1)
├── MODULE2.C (Модуль 2)
├── SHARED.H (Общие определения)
└── SYSTEM.CNF
```
---
### **2. Общий заголовок (SHARED.H)**
```c
// Структура для общих переменных
typedef struct {
int counter;
char message[32];
} SharedData;
// Заголовок модуля (должен быть одинаковым во всех модулях)
typedef void (*ModuleFunc)(SharedData*);
typedef struct {
uint32_t magic; // Магическое число 0x55AA1234
ModuleFunc entry_point; // Точка входа
uint32_t size; // Размер модуля
} ModuleHeader;
```
---
### **3. Основная программа (MAIN.C)**
```c
#include <sys/types.h>
#include <libetc.h>
#include <libgte.h>
#include <libcd.h>
#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 в секторах
SharedData shared_data; // Общие данные
void load_and_run_module(int sector, int size) {
// 1. Загрузка модуля в фиксированный адрес
CdRead(sector, (uint32_t*)MODULE_LOAD_ADDR, size);
CdReadSync(0);
// 2. Проверка заголовка
ModuleHeader *header = (ModuleHeader*)MODULE_LOAD_ADDR;
if (header->magic != 0x55AA1234) {
FntPrint("Invalid module!\n");
return;
}
// 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);
// Загрузить и выполнить MODULE2
FntPrint("Loading MODULE2...\n");
load_and_run_module(MODULE2_SECTOR, MODULE2_SIZE);
VSync(0);
FntFlush(-1);
VSync(0);
}
return 0;
}
```
---
### **4. Модуль 1 (MODULE1.C)**
```c
#include "SHARED.H"
void module_entry(SharedData *shared) {
// Изменяем общие данные
shared->counter++;
sprintf(shared->message, "MODULE1 was here!");
// Выводим сообщение (в реальности используйте FntPrint из основной программы)
// Здесь просто пример доступа к данным
}
// Важно: заголовок должен быть в конце файла!
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,
.size = 0
};
```
---
### **6. Компиляция и запись на диск**
1. Скомпилируйте каждый модуль **отдельно**:
```bash
ccpsx MAIN.C -o MAIN.EXE
ccpsx MODULE1.C -o MODULE1.BIN
ccpsx MODULE2.C -o MODULE2.BIN
```
2. Запишите на диск, указав **точные сектора**:
```
MAIN.EXE -> Сектор 0
MODULE1.BIN -> Сектор 1000 (как указано в MAIN.C)
MODULE2.BIN -> Сектор 1100
```
3. В `SYSTEM.CNF` укажите:
```
BOOT = cdrom:\MAIN.EXE;1
```
---
### **7. Как это работает**
1. **Основная программа**:
- Загружает модули в `0x80030000` через `CdRead()`.
- Проверяет магическое число в заголовке.
- Вызывает `entry_point`, передавая указатель на общие данные.
2. **Модули**:
- Компилируются с **заголовком** в начале.
- Имеют доступ к `SharedData` через переданный указатель.
- Разрешены **только операции с данными** (нельзя использовать PsyQ напрямую).
3. **Общие переменные**:
- Расположены в основной программе.
- Модули получают к ним доступ через указатель.
---
### **8. Ограничения безопасности**
- Все модули **должны доверять** друг другу.
- Нет защиты от **переполнения буфера** (адрес загрузки фиксирован).
- Модули не должны **переопределять системные вызовы**.
---
### **9. Оптимизации**
- Используйте **DMA** для ускорения загрузки.
- Добавьте **CRC-проверку** модулей в заголовке.
- Для сложных модулей применяйте **релокацию** (но это сложнее).
Этот подход используется в таких играх, как **Metal Gear Solid** (для загрузки скриптовых модулей).
________________