mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
(WIP) new binary format
This commit is contained in:
parent
9ab7b9bb14
commit
c6da4b891a
10 changed files with 128 additions and 219 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
|
@ -73,7 +73,7 @@
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/core/tests/build/core_tests", // Remplacez par le chemin de votre exécutable
|
"program": "${workspaceFolder}/core/tests/build/core_tests", // Remplacez par le chemin de votre exécutable
|
||||||
"args": [],
|
"args": ["[vm]"],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/core/tests/build",
|
"cwd": "${workspaceFolder}/core/tests/build",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
|
|
|
||||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
|
@ -109,7 +109,9 @@
|
||||||
"serializers.h": "c",
|
"serializers.h": "c",
|
||||||
"ni_parser.h": "c",
|
"ni_parser.h": "c",
|
||||||
"*.m": "cpp",
|
"*.m": "cpp",
|
||||||
"*.inc": "cpp"
|
"*.inc": "cpp",
|
||||||
|
"chip32_binary_format.h": "c",
|
||||||
|
"hash_map": "c"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +365,7 @@ bool Assembler::BuildBinary(std::vector<uint8_t> &program, Result &result)
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// PHASE 1: Créer les sections temporaires
|
// PHASE 1: Créer les sections temporaires
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
std::vector<uint8_t> dataSection; // DC - ROM constants only
|
std::vector<uint8_t> constSection; // DC - ROM constants only
|
||||||
std::vector<uint8_t> codeSection; // Executable code
|
std::vector<uint8_t> codeSection; // Executable code
|
||||||
std::vector<uint8_t> initDataSection; // DV values + DZ zeros (RAM init)
|
std::vector<uint8_t> initDataSection; // DV values + DZ zeros (RAM init)
|
||||||
|
|
||||||
|
|
@ -471,10 +471,10 @@ bool Assembler::BuildBinary(std::vector<uint8_t> &program, Result &result)
|
||||||
|
|
||||||
if (!isDvInitData)
|
if (!isDvInitData)
|
||||||
{
|
{
|
||||||
// C'est une vraie constante DC - va dans dataSection
|
// C'est une vraie constante DC - va dans constSection
|
||||||
std::copy(i.compiledArgs.begin(),
|
std::copy(i.compiledArgs.begin(),
|
||||||
i.compiledArgs.end(),
|
i.compiledArgs.end(),
|
||||||
std::back_inserter(dataSection));
|
std::back_inserter(constSection));
|
||||||
|
|
||||||
result.constantsSize += i.compiledArgs.size();
|
result.constantsSize += i.compiledArgs.size();
|
||||||
}
|
}
|
||||||
|
|
@ -511,7 +511,7 @@ bool Assembler::BuildBinary(std::vector<uint8_t> &program, Result &result)
|
||||||
chip32_binary_header_t header;
|
chip32_binary_header_t header;
|
||||||
chip32_binary_header_init(&header);
|
chip32_binary_header_init(&header);
|
||||||
|
|
||||||
header.data_size = static_cast<uint32_t>(dataSection.size());
|
header.const_size = static_cast<uint32_t>(constSection.size());
|
||||||
header.bss_size = bssSize;
|
header.bss_size = bssSize;
|
||||||
header.code_size = static_cast<uint32_t>(codeSection.size());
|
header.code_size = static_cast<uint32_t>(codeSection.size());
|
||||||
header.entry_point = entryPoint;
|
header.entry_point = entryPoint;
|
||||||
|
|
@ -530,7 +530,7 @@ bool Assembler::BuildBinary(std::vector<uint8_t> &program, Result &result)
|
||||||
|
|
||||||
uint32_t bytesWritten = chip32_binary_write(
|
uint32_t bytesWritten = chip32_binary_write(
|
||||||
&header,
|
&header,
|
||||||
dataSection.empty() ? nullptr : dataSection.data(),
|
constSection.empty() ? nullptr : constSection.data(),
|
||||||
codeSection.empty() ? nullptr : codeSection.data(),
|
codeSection.empty() ? nullptr : codeSection.data(),
|
||||||
initDataSection.empty() ? nullptr : initDataSection.data(),
|
initDataSection.empty() ? nullptr : initDataSection.data(),
|
||||||
program.data(),
|
program.data(),
|
||||||
|
|
@ -548,8 +548,8 @@ bool Assembler::BuildBinary(std::vector<uint8_t> &program, Result &result)
|
||||||
// PHASE 7: Remplir les statistiques
|
// PHASE 7: Remplir les statistiques
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
result.ramUsageSize = bssSize;
|
result.ramUsageSize = bssSize;
|
||||||
result.romUsageSize = header.data_size + header.code_size;
|
result.romUsageSize = header.const_size + header.code_size;
|
||||||
result.constantsSize = header.data_size;
|
result.constantsSize = header.const_size;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,94 +13,92 @@ _Static_assert(sizeof(chip32_binary_header_t) == 28, "Header must be 28 bytes");
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
chip32_binary_error_t chip32_binary_load(
|
chip32_binary_error_t chip32_binary_load(
|
||||||
|
chip32_ctx_t *ctx,
|
||||||
uint8_t* binary,
|
uint8_t* binary,
|
||||||
uint32_t size,
|
uint32_t binary_size,
|
||||||
chip32_loaded_binary_t* out_loaded
|
uint8_t* ram,
|
||||||
|
uint32_t ram_size,
|
||||||
|
chip32_binary_stats_t *out_stats
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!binary || !out_loaded) {
|
memset(ctx, 0, sizeof(ctx));
|
||||||
|
ctx->stack_size = 512; // Can be changed outside this function
|
||||||
|
|
||||||
|
// Clear RAM
|
||||||
|
memset(ram, 0, ram_size);
|
||||||
|
|
||||||
|
chip32_binary_header_t header;
|
||||||
|
|
||||||
|
if (!binary || !ctx) {
|
||||||
return CHIP32_BIN_ERR_NULL_POINTER;
|
return CHIP32_BIN_ERR_NULL_POINTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear output structure
|
|
||||||
memset(out_loaded, 0, sizeof(chip32_loaded_binary_t));
|
|
||||||
|
|
||||||
// Check minimum size
|
// Check minimum size
|
||||||
if (size < sizeof(chip32_binary_header_t)) {
|
if (binary_size < sizeof(chip32_binary_header_t)) {
|
||||||
out_loaded->error = CHIP32_BIN_ERR_TOO_SMALL;
|
|
||||||
return CHIP32_BIN_ERR_TOO_SMALL;
|
return CHIP32_BIN_ERR_TOO_SMALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy header
|
// Copy header
|
||||||
memcpy(&out_loaded->header, binary, sizeof(chip32_binary_header_t));
|
memcpy(&header, binary, sizeof(chip32_binary_header_t));
|
||||||
|
|
||||||
// Verify magic number
|
// Verify magic number
|
||||||
if (out_loaded->header.magic != CHIP32_MAGIC) {
|
if (header.magic != CHIP32_MAGIC) {
|
||||||
out_loaded->error = CHIP32_BIN_ERR_INVALID_MAGIC;
|
|
||||||
return CHIP32_BIN_ERR_INVALID_MAGIC;
|
return CHIP32_BIN_ERR_INVALID_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check version
|
// Check version
|
||||||
if (out_loaded->header.version > CHIP32_VERSION) {
|
if (header.version > CHIP32_VERSION) {
|
||||||
out_loaded->error = CHIP32_BIN_ERR_UNSUPPORTED_VERSION;
|
|
||||||
return CHIP32_BIN_ERR_UNSUPPORTED_VERSION;
|
return CHIP32_BIN_ERR_UNSUPPORTED_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate expected size
|
// Calculate expected size
|
||||||
uint32_t expected_size = sizeof(chip32_binary_header_t) +
|
uint32_t expected_size = sizeof(chip32_binary_header_t) +
|
||||||
out_loaded->header.data_size +
|
header.const_size +
|
||||||
out_loaded->header.code_size +
|
header.code_size +
|
||||||
out_loaded->header.init_data_size;
|
header.init_data_size;
|
||||||
|
|
||||||
if (size != expected_size) {
|
if (binary_size != expected_size) {
|
||||||
out_loaded->error = CHIP32_BIN_ERR_SIZE_MISMATCH;
|
|
||||||
return CHIP32_BIN_ERR_SIZE_MISMATCH;
|
return CHIP32_BIN_ERR_SIZE_MISMATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set section pointers
|
// Set section pointers
|
||||||
uint32_t offset = sizeof(chip32_binary_header_t);
|
uint32_t offset = sizeof(chip32_binary_header_t);
|
||||||
|
|
||||||
if (out_loaded->header.data_size > 0) {
|
// Skip header for ROM executable (must start at a valide code address)
|
||||||
out_loaded->data_section = binary + offset;
|
ctx->rom.mem = binary + offset;
|
||||||
offset += out_loaded->header.data_size;
|
ctx->rom.size = binary_size - offset;
|
||||||
}
|
ctx->rom.addr = 0;
|
||||||
|
|
||||||
if (out_loaded->header.code_size > 0) {
|
// RAM and ROM are in the same logical memory plane
|
||||||
out_loaded->code_section = binary + offset;
|
// So we set it begin after the ROM (why not)
|
||||||
offset += out_loaded->header.code_size;
|
ctx->ram.mem = ram;
|
||||||
}
|
ctx->ram.addr = ctx->rom.size;
|
||||||
|
ctx->ram.size = ram_size;
|
||||||
|
|
||||||
if (out_loaded->header.init_data_size > 0) {
|
// Set entry point (DATA size + entry point offset in CODE)
|
||||||
out_loaded->init_data_section = binary + offset;
|
ctx->registers[PC] = header.entry_point;
|
||||||
}
|
|
||||||
|
|
||||||
out_loaded->error = CHIP32_BIN_OK;
|
// Load data initialized values
|
||||||
return CHIP32_BIN_OK;
|
const uint8_t *data = binary + header.code_size;
|
||||||
}
|
memcpy(ram, data, header.init_data_size);
|
||||||
|
|
||||||
void chip32_binary_get_stats(
|
|
||||||
const chip32_loaded_binary_t* loaded,
|
|
||||||
chip32_binary_stats_t* out_stats
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (!loaded || !out_stats) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_stats->data_size = loaded->header.data_size;
|
out_stats->const_size = header.const_size;
|
||||||
out_stats->bss_size = loaded->header.bss_size;
|
out_stats->bss_size = header.bss_size;
|
||||||
out_stats->code_size = loaded->header.code_size;
|
out_stats->code_size = header.code_size;
|
||||||
out_stats->init_data_size = loaded->header.init_data_size;
|
out_stats->init_data_size = header.init_data_size;
|
||||||
|
|
||||||
out_stats->total_file_size = sizeof(chip32_binary_header_t) +
|
out_stats->total_file_size = sizeof(chip32_binary_header_t) +
|
||||||
loaded->header.data_size +
|
header.const_size +
|
||||||
loaded->header.code_size +
|
header.code_size +
|
||||||
loaded->header.init_data_size;
|
header.init_data_size;
|
||||||
|
|
||||||
out_stats->total_rom_size = loaded->header.data_size +
|
out_stats->total_rom_size = header.const_size +
|
||||||
loaded->header.code_size;
|
header.code_size;
|
||||||
|
|
||||||
out_stats->total_ram_size = loaded->header.bss_size;
|
out_stats->total_ram_size = header.bss_size;
|
||||||
|
|
||||||
|
return CHIP32_BIN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* chip32_binary_error_string(chip32_binary_error_t error)
|
const char* chip32_binary_error_string(chip32_binary_error_t error)
|
||||||
|
|
@ -146,7 +144,7 @@ uint32_t chip32_binary_calculate_size(const chip32_binary_header_t* header)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sizeof(chip32_binary_header_t) +
|
return sizeof(chip32_binary_header_t) +
|
||||||
header->data_size +
|
header->const_size +
|
||||||
header->code_size +
|
header->code_size +
|
||||||
header->init_data_size;
|
header->init_data_size;
|
||||||
}
|
}
|
||||||
|
|
@ -178,12 +176,12 @@ uint32_t chip32_binary_write(
|
||||||
offset += sizeof(chip32_binary_header_t);
|
offset += sizeof(chip32_binary_header_t);
|
||||||
|
|
||||||
// Write DATA section
|
// Write DATA section
|
||||||
if (header->data_size > 0) {
|
if (header->const_size > 0) {
|
||||||
if (!data_section) {
|
if (!data_section) {
|
||||||
return 0; // Data expected but NULL pointer
|
return 0; // Data expected but NULL pointer
|
||||||
}
|
}
|
||||||
memcpy(out_buffer + offset, data_section, header->data_size);
|
memcpy(out_buffer + offset, data_section, header->const_size);
|
||||||
offset += header->data_size;
|
offset += header->const_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write CODE section
|
// Write CODE section
|
||||||
|
|
@ -207,35 +205,6 @@ uint32_t chip32_binary_write(
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// RAM INITIALIZATION HELPER
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
uint32_t chip32_binary_init_ram(
|
|
||||||
const chip32_loaded_binary_t* loaded,
|
|
||||||
uint8_t* ram_buffer,
|
|
||||||
uint32_t ram_size
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (!loaded || !ram_buffer) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if binary has init data
|
|
||||||
if (loaded->header.init_data_size == 0 || !loaded->init_data_section) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy init data to RAM (respect buffer limits)
|
|
||||||
uint32_t copy_size = loaded->header.init_data_size;
|
|
||||||
if (copy_size > ram_size) {
|
|
||||||
copy_size = ram_size; // Truncate if RAM is smaller
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(ram_buffer, loaded->init_data_section, copy_size);
|
|
||||||
|
|
||||||
return copy_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// DEBUG/UTILITY FUNCTIONS
|
// DEBUG/UTILITY FUNCTIONS
|
||||||
|
|
@ -260,7 +229,7 @@ void chip32_binary_print_header(const chip32_binary_header_t* header)
|
||||||
printf(" (has init data)");
|
printf(" (has init data)");
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("DATA section: %u bytes (ROM constants)\n", header->data_size);
|
printf("DATA section: %u bytes (ROM constants)\n", header->const_size);
|
||||||
printf("BSS section: %u bytes (Total RAM: DV+DZ)\n", header->bss_size);
|
printf("BSS section: %u bytes (Total RAM: DV+DZ)\n", header->bss_size);
|
||||||
printf("CODE section: %u bytes\n", header->code_size);
|
printf("CODE section: %u bytes\n", header->code_size);
|
||||||
printf("Entry point: 0x%08X\n", header->entry_point);
|
printf("Entry point: 0x%08X\n", header->entry_point);
|
||||||
|
|
@ -275,7 +244,7 @@ void chip32_binary_print_stats(const chip32_binary_stats_t* stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("=== Chip32 Binary Statistics ===\n");
|
printf("=== Chip32 Binary Statistics ===\n");
|
||||||
printf("DATA section: %u bytes (ROM, initialized)\n", stats->data_size);
|
printf("DATA section: %u bytes (ROM, initialized)\n", stats->const_size);
|
||||||
printf("BSS section: %u bytes (RAM, DV+DZ)\n", stats->bss_size);
|
printf("BSS section: %u bytes (RAM, DV+DZ)\n", stats->bss_size);
|
||||||
printf("CODE section: %u bytes (ROM, executable)\n", stats->code_size);
|
printf("CODE section: %u bytes (ROM, executable)\n", stats->code_size);
|
||||||
printf("Init data: %u bytes (RAM initialization)\n", stats->init_data_size);
|
printf("Init data: %u bytes (RAM initialization)\n", stats->init_data_size);
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,24 @@
|
||||||
* - Initial RAM values: DV values + zeros for DZ areas
|
* - Initial RAM values: DV values + zeros for DZ areas
|
||||||
* - Size = sum of all DV and DZ declarations
|
* - Size = sum of all DV and DZ declarations
|
||||||
* - Layout matches RAM layout exactly
|
* - Layout matches RAM layout exactly
|
||||||
|
*
|
||||||
|
*
|
||||||
|
|
||||||
|
+--------------------------------------+
|
||||||
|
| Chip32 Header | <-- Début du fichier
|
||||||
|
| (Magic, Versions, Sizes, Entry...) |
|
||||||
|
+--------------------------------------+
|
||||||
|
| CONST Section (DV) | <-- Données initialisées
|
||||||
|
| (Variables globales initialisées) | e.g., const int x = 5;
|
||||||
|
+--------------------------------------+
|
||||||
|
| CODE Section | <-- Instructions du programme
|
||||||
|
| (Les opcodes et leurs opérandes) |
|
||||||
|
+--------------------------------------+
|
||||||
|
| DATA Section (Optional) | <-- Données pour l'initialisation de la RAM (copie de DV)
|
||||||
|
| (Contient les valeurs initiales pour la RAM)
|
||||||
|
+--------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CHIP32_BINARY_FORMAT_H
|
#ifndef CHIP32_BINARY_FORMAT_H
|
||||||
|
|
@ -44,6 +62,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "chip32_vm.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -74,7 +93,7 @@ typedef struct {
|
||||||
uint32_t magic; // Magic number "C32\0"
|
uint32_t magic; // Magic number "C32\0"
|
||||||
uint16_t version; // Format version
|
uint16_t version; // Format version
|
||||||
uint16_t flags; // Feature flags
|
uint16_t flags; // Feature flags
|
||||||
uint32_t data_size; // Size of DATA section in bytes (ROM constants)
|
uint32_t const_size; // Size of DATA section in bytes (ROM constants)
|
||||||
uint32_t bss_size; // Total RAM size (DV + DZ)
|
uint32_t bss_size; // Total RAM size (DV + DZ)
|
||||||
uint32_t code_size; // Size of CODE section in bytes
|
uint32_t code_size; // Size of CODE section in bytes
|
||||||
uint32_t entry_point; // Entry point offset in CODE section
|
uint32_t entry_point; // Entry point offset in CODE section
|
||||||
|
|
@ -82,18 +101,9 @@ typedef struct {
|
||||||
} chip32_binary_header_t;
|
} chip32_binary_header_t;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
// Loaded binary structure
|
|
||||||
typedef struct {
|
|
||||||
chip32_binary_header_t header;
|
|
||||||
uint8_t* data_section; // Points to DATA section (ROM)
|
|
||||||
uint8_t* code_section; // Points to CODE section
|
|
||||||
uint8_t* init_data_section; // Points to INIT DATA (RAM initialization)
|
|
||||||
chip32_binary_error_t error;
|
|
||||||
} chip32_loaded_binary_t;
|
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t data_size; // ROM constants
|
uint32_t const_size; // ROM constants
|
||||||
uint32_t bss_size; // Total RAM needed
|
uint32_t bss_size; // Total RAM needed
|
||||||
uint32_t code_size; // Executable code
|
uint32_t code_size; // Executable code
|
||||||
uint32_t init_data_size; // RAM initialization data
|
uint32_t init_data_size; // RAM initialization data
|
||||||
|
|
@ -114,20 +124,14 @@ typedef struct {
|
||||||
* @return Error code
|
* @return Error code
|
||||||
*/
|
*/
|
||||||
chip32_binary_error_t chip32_binary_load(
|
chip32_binary_error_t chip32_binary_load(
|
||||||
|
chip32_ctx_t *ctx,
|
||||||
uint8_t* binary,
|
uint8_t* binary,
|
||||||
uint32_t size,
|
uint32_t binary_size,
|
||||||
chip32_loaded_binary_t* out_loaded
|
uint8_t* ram,
|
||||||
|
uint32_t ram_size,
|
||||||
|
chip32_binary_stats_t *out_stats
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get statistics from a loaded binary
|
|
||||||
* @param loaded Loaded binary structure
|
|
||||||
* @param out_stats Output statistics
|
|
||||||
*/
|
|
||||||
void chip32_binary_get_stats(
|
|
||||||
const chip32_loaded_binary_t* loaded,
|
|
||||||
chip32_binary_stats_t* out_stats
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get error string from error code
|
* Get error string from error code
|
||||||
|
|
@ -156,7 +160,7 @@ uint32_t chip32_binary_calculate_size(const chip32_binary_header_t* header);
|
||||||
/**
|
/**
|
||||||
* Write a complete binary to memory
|
* Write a complete binary to memory
|
||||||
* @param header Binary header
|
* @param header Binary header
|
||||||
* @param data_section DATA section content (can be NULL if data_size is 0)
|
* @param data_section DATA section content (can be NULL if const_size is 0)
|
||||||
* @param code_section CODE section content (can be NULL if code_size is 0)
|
* @param code_section CODE section content (can be NULL if code_size is 0)
|
||||||
* @param init_data_section INIT DATA section (can be NULL if init_data_size is 0)
|
* @param init_data_section INIT DATA section (can be NULL if init_data_size is 0)
|
||||||
* @param out_buffer Output buffer (must be large enough)
|
* @param out_buffer Output buffer (must be large enough)
|
||||||
|
|
@ -172,24 +176,6 @@ uint32_t chip32_binary_write(
|
||||||
uint32_t buffer_size
|
uint32_t buffer_size
|
||||||
);
|
);
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// RAM INITIALIZATION HELPER
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize RAM from binary INIT DATA section
|
|
||||||
* This copies all initial values (DV) and zeros (DZ) to RAM
|
|
||||||
* @param loaded Loaded binary with init data
|
|
||||||
* @param ram_buffer Destination RAM buffer
|
|
||||||
* @param ram_size Size of RAM buffer
|
|
||||||
* @return Number of bytes copied, or 0 if no init data
|
|
||||||
*/
|
|
||||||
uint32_t chip32_binary_init_ram(
|
|
||||||
const chip32_loaded_binary_t* loaded,
|
|
||||||
uint8_t* ram_buffer,
|
|
||||||
uint32_t ram_size
|
|
||||||
);
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// DEBUG/UTILITY FUNCTIONS
|
// DEBUG/UTILITY FUNCTIONS
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ public:
|
||||||
m_syscallHandler = std::bind(&Machine::HandleSyscall, this,
|
m_syscallHandler = std::bind(&Machine::HandleSyscall, this,
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2);
|
std::placeholders::_2);
|
||||||
|
m_ram.resize(1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
@ -64,12 +65,15 @@ public:
|
||||||
|
|
||||||
result.Print();
|
result.Print();
|
||||||
|
|
||||||
// Load binary using new format
|
// Load binary using executable format
|
||||||
chip32_loaded_binary_t loaded;
|
chip32_binary_stats_t stats;
|
||||||
chip32_binary_error_t error = chip32_binary_load(
|
chip32_binary_error_t error = chip32_binary_load(
|
||||||
|
&ctx,
|
||||||
program.data(),
|
program.data(),
|
||||||
static_cast<uint32_t>(program.size()),
|
static_cast<uint32_t>(program.size()),
|
||||||
&loaded
|
m_ram.data(),
|
||||||
|
static_cast<uint32_t>(m_ram.size()),
|
||||||
|
&stats
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error != CHIP32_BIN_OK) {
|
if (error != CHIP32_BIN_OK) {
|
||||||
|
|
@ -78,29 +82,6 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate and initialize RAM
|
|
||||||
m_ram.resize(loaded.header.bss_size);
|
|
||||||
|
|
||||||
uint32_t init_bytes = chip32_binary_init_ram(&loaded, m_ram.data(), m_ram.size());
|
|
||||||
|
|
||||||
if (init_bytes > 0) {
|
|
||||||
std::cout << "RAM initialized: " << init_bytes << " bytes" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup VM context
|
|
||||||
memset(&ctx, 0, sizeof(ctx));
|
|
||||||
ctx.stack_size = 512;
|
|
||||||
|
|
||||||
// ROM = DATA + CODE (contiguous in loaded binary)
|
|
||||||
ctx.rom.mem = loaded.data_section;
|
|
||||||
ctx.rom.addr = 0;
|
|
||||||
ctx.rom.size = loaded.header.data_size + loaded.header.code_size;
|
|
||||||
|
|
||||||
// RAM
|
|
||||||
ctx.ram.mem = m_ram.data();
|
|
||||||
ctx.ram.addr = ctx.rom.size;
|
|
||||||
ctx.ram.size = m_ram.size();
|
|
||||||
|
|
||||||
// Set syscall handler using wrapper
|
// Set syscall handler using wrapper
|
||||||
ctx.syscall = SyscallWrapper;
|
ctx.syscall = SyscallWrapper;
|
||||||
ctx.user_data = this;
|
ctx.user_data = this;
|
||||||
|
|
@ -108,8 +89,6 @@ public:
|
||||||
// Initialize VM
|
// Initialize VM
|
||||||
chip32_initialize(&ctx);
|
chip32_initialize(&ctx);
|
||||||
|
|
||||||
// Set entry point (DATA size + entry point offset in CODE)
|
|
||||||
ctx.registers[PC] = loaded.header.data_size + loaded.header.entry_point;
|
|
||||||
|
|
||||||
std::cout << "Starting execution at PC=0x" << std::hex << ctx.registers[PC]
|
std::cout << "Starting execution at PC=0x" << std::hex << ctx.registers[PC]
|
||||||
<< std::dec << std::endl;
|
<< std::dec << std::endl;
|
||||||
|
|
@ -281,13 +260,6 @@ public:
|
||||||
uint8_t *ram_buffer,
|
uint8_t *ram_buffer,
|
||||||
uint32_t ram_size)
|
uint32_t ram_size)
|
||||||
{
|
{
|
||||||
// Charger et valider le binaire
|
|
||||||
chip32_loaded_binary_t loaded;
|
|
||||||
chip32_binary_error_t err = chip32_binary_load(
|
|
||||||
binary.data(),
|
|
||||||
static_cast<uint32_t>(binary.size()),
|
|
||||||
&loaded
|
|
||||||
);
|
|
||||||
|
|
||||||
if (err != CHIP32_BIN_OK)
|
if (err != CHIP32_BIN_OK)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -104,14 +104,14 @@ void chip32_initialize(chip32_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
memset(ctx->ram.mem, 0, ctx->ram.size);
|
memset(ctx->ram.mem, 0, ctx->ram.size);
|
||||||
memset(ctx->registers, 0, REGISTER_COUNT * sizeof(uint32_t));
|
memset(ctx->registers, 0, REGISTER_COUNT * sizeof(uint32_t));
|
||||||
ctx->instrCount = 0;
|
ctx->instr_count = 0;
|
||||||
ctx->registers[SP] = ctx->ram.size;
|
ctx->registers[SP] = ctx->ram.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
chip32_result_t chip32_run(chip32_ctx_t *ctx)
|
chip32_result_t chip32_run(chip32_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
chip32_result_t result = VM_OK;
|
chip32_result_t result = VM_OK;
|
||||||
while ((ctx->max_instr == 0) || (ctx->instrCount < ctx->max_instr))
|
while ((ctx->max_instr == 0) || (ctx->instr_count < ctx->max_instr))
|
||||||
{
|
{
|
||||||
result = chip32_step(ctx);
|
result = chip32_step(ctx);
|
||||||
|
|
||||||
|
|
@ -434,7 +434,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->registers[PC]++;
|
ctx->registers[PC]++;
|
||||||
ctx->instrCount++;
|
ctx->instr_count++;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ struct chip32_ctx_t
|
||||||
virtual_mem_t rom;
|
virtual_mem_t rom;
|
||||||
virtual_mem_t ram;
|
virtual_mem_t ram;
|
||||||
uint16_t stack_size;
|
uint16_t stack_size;
|
||||||
uint32_t instrCount;
|
uint32_t instr_count;
|
||||||
uint16_t prog_size;
|
uint16_t prog_size;
|
||||||
uint32_t max_instr;
|
uint32_t max_instr;
|
||||||
uint32_t registers[REGISTER_COUNT];
|
uint32_t registers[REGISTER_COUNT];
|
||||||
|
|
|
||||||
|
|
@ -363,7 +363,7 @@ TEST_CASE("Binary format validation")
|
||||||
REQUIRE(loaded.header.magic == CHIP32_MAGIC);
|
REQUIRE(loaded.header.magic == CHIP32_MAGIC);
|
||||||
REQUIRE(loaded.header.version == CHIP32_VERSION);
|
REQUIRE(loaded.header.version == CHIP32_VERSION);
|
||||||
REQUIRE((loaded.header.flags & CHIP32_FLAG_HAS_INIT_DATA) != 0);
|
REQUIRE((loaded.header.flags & CHIP32_FLAG_HAS_INIT_DATA) != 0);
|
||||||
REQUIRE(loaded.header.data_size > 0); // Has ROM constants
|
REQUIRE(loaded.header.const_size > 0); // Has ROM constants
|
||||||
REQUIRE(loaded.header.bss_size > 0); // Has RAM
|
REQUIRE(loaded.header.bss_size > 0); // Has RAM
|
||||||
REQUIRE(loaded.header.code_size > 0); // Has code
|
REQUIRE(loaded.header.code_size > 0); // Has code
|
||||||
REQUIRE(loaded.header.init_data_size == loaded.header.bss_size); // Must match
|
REQUIRE(loaded.header.init_data_size == loaded.header.bss_size); // Must match
|
||||||
|
|
|
||||||
|
|
@ -24,59 +24,37 @@ THE SOFTWARE.
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "chip32_assembler.h"
|
#include "chip32_machine.h" // Inclure chip32_machine.h au lieu de assembler et vm
|
||||||
#include "chip32_vm.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Purpose: test all opcodes
|
Purpose: test all opcodes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void hexdump(void *ptr, int buflen);
|
// Suppression des fonctions et classes de configuration de la VM
|
||||||
|
// qui sont maintenant encapsulées dans Chip32::Machine.
|
||||||
static uint8_t story_player_syscall(chip32_ctx_t *ctx, uint8_t code)
|
|
||||||
{
|
|
||||||
uint8_t retCode = SYSCALL_RET_OK;
|
|
||||||
|
|
||||||
return retCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class VmTestContext
|
class VmTestContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VmTestContext() {
|
VmTestContext() {
|
||||||
|
// La RAM est allouée et initialisée à l'intérieur de QuickExecute
|
||||||
|
// de la classe Machine. On peut laisser le constructeur vide.
|
||||||
}
|
}
|
||||||
|
|
||||||
void Execute(const std::string &assemblyCode)
|
void Execute(const std::string &assemblyCode)
|
||||||
{
|
{
|
||||||
// --------- BUILD BINARY ---------
|
// Utiliser la méthode QuickExecute de Machine pour Parse, Build et Run
|
||||||
REQUIRE( assembler.Parse(assemblyCode) == true );
|
machine.QuickExecute(assemblyCode);
|
||||||
REQUIRE( assembler.BuildBinary(program, result) == true );
|
|
||||||
result.Print();
|
|
||||||
|
|
||||||
chip32_ctx.stack_size = 512;
|
// Vérification de base: le parsing et le build doivent réussir
|
||||||
|
REQUIRE( machine.parseResult == true );
|
||||||
|
REQUIRE( machine.buildResult == true );
|
||||||
|
|
||||||
chip32_ctx.rom.mem = program.data();
|
// Vérification que l'exécution a fini normalement (HALT)
|
||||||
chip32_ctx.rom.addr = 18*1024;
|
REQUIRE( machine.runResult == VM_FINISHED );
|
||||||
chip32_ctx.rom.size = program.size();
|
|
||||||
|
|
||||||
chip32_ctx.ram.mem = data;
|
|
||||||
chip32_ctx.ram.addr = 56 *1024,
|
|
||||||
chip32_ctx.ram.size = sizeof(data);
|
|
||||||
|
|
||||||
chip32_ctx.syscall = story_player_syscall;
|
|
||||||
|
|
||||||
chip32_initialize(&chip32_ctx);
|
|
||||||
chip32_result_t runResult = chip32_run(&chip32_ctx);
|
|
||||||
REQUIRE( runResult == VM_FINISHED );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[8*1024];
|
Chip32::Machine machine; // Instance de la Machine à utiliser pour les tests
|
||||||
std::vector<uint8_t> program;
|
|
||||||
Chip32::Assembler assembler;
|
|
||||||
Chip32::Result result;
|
|
||||||
chip32_ctx_t chip32_ctx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -89,7 +67,8 @@ TEST_CASE_METHOD(VmTestContext, "MUL", "[vm]") {
|
||||||
)";
|
)";
|
||||||
Execute(test1);
|
Execute(test1);
|
||||||
|
|
||||||
uint32_t result = chip32_ctx.registers[R0];
|
// Accéder directement aux registres de la Machine pour vérifier le résultat
|
||||||
|
uint32_t result = machine.ctx.registers[R0];
|
||||||
REQUIRE (result == 37 * 0x695);
|
REQUIRE (result == 37 * 0x695);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,6 +81,7 @@ TEST_CASE_METHOD(VmTestContext, "DIV", "[vm]") {
|
||||||
)";
|
)";
|
||||||
Execute(test1);
|
Execute(test1);
|
||||||
|
|
||||||
uint32_t result = chip32_ctx.registers[R0];
|
// Accéder directement aux registres de la Machine pour vérifier le résultat
|
||||||
|
uint32_t result = machine.ctx.registers[R0];
|
||||||
REQUIRE (result == (int)(37/8));
|
REQUIRE (result == (int)(37/8));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue