diff --git a/.vscode/launch.json b/.vscode/launch.json index 8aed7f4..1b9de62 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -73,7 +73,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/core/tests/build/core_tests", // Remplacez par le chemin de votre exécutable - "args": [], + "args": ["[vm]"], "stopAtEntry": false, "cwd": "${workspaceFolder}/core/tests/build", "environment": [], diff --git a/.vscode/settings.json b/.vscode/settings.json index 030c40d..4a2bd41 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -109,7 +109,9 @@ "serializers.h": "c", "ni_parser.h": "c", "*.m": "cpp", - "*.inc": "cpp" + "*.inc": "cpp", + "chip32_binary_format.h": "c", + "hash_map": "c" } } \ No newline at end of file diff --git a/core/chip32/chip32_assembler.cpp b/core/chip32/chip32_assembler.cpp index 38924a7..e0050e5 100644 --- a/core/chip32/chip32_assembler.cpp +++ b/core/chip32/chip32_assembler.cpp @@ -365,7 +365,7 @@ bool Assembler::BuildBinary(std::vector &program, Result &result) // ======================================================================== // PHASE 1: Créer les sections temporaires // ======================================================================== - std::vector dataSection; // DC - ROM constants only + std::vector constSection; // DC - ROM constants only std::vector codeSection; // Executable code std::vector initDataSection; // DV values + DZ zeros (RAM init) @@ -471,10 +471,10 @@ bool Assembler::BuildBinary(std::vector &program, Result &result) 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(), i.compiledArgs.end(), - std::back_inserter(dataSection)); + std::back_inserter(constSection)); result.constantsSize += i.compiledArgs.size(); } @@ -511,7 +511,7 @@ bool Assembler::BuildBinary(std::vector &program, Result &result) chip32_binary_header_t header; chip32_binary_header_init(&header); - header.data_size = static_cast(dataSection.size()); + header.const_size = static_cast(constSection.size()); header.bss_size = bssSize; header.code_size = static_cast(codeSection.size()); header.entry_point = entryPoint; @@ -530,7 +530,7 @@ bool Assembler::BuildBinary(std::vector &program, Result &result) uint32_t bytesWritten = chip32_binary_write( &header, - dataSection.empty() ? nullptr : dataSection.data(), + constSection.empty() ? nullptr : constSection.data(), codeSection.empty() ? nullptr : codeSection.data(), initDataSection.empty() ? nullptr : initDataSection.data(), program.data(), @@ -548,8 +548,8 @@ bool Assembler::BuildBinary(std::vector &program, Result &result) // PHASE 7: Remplir les statistiques // ======================================================================== result.ramUsageSize = bssSize; - result.romUsageSize = header.data_size + header.code_size; - result.constantsSize = header.data_size; + result.romUsageSize = header.const_size + header.code_size; + result.constantsSize = header.const_size; return true; } diff --git a/core/chip32/chip32_binary_format.c b/core/chip32/chip32_binary_format.c index 7499165..7bc3987 100644 --- a/core/chip32/chip32_binary_format.c +++ b/core/chip32/chip32_binary_format.c @@ -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_ctx_t *ctx, uint8_t* binary, - uint32_t size, - chip32_loaded_binary_t* out_loaded + uint32_t binary_size, + 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; } - - // Clear output structure - memset(out_loaded, 0, sizeof(chip32_loaded_binary_t)); - + // Check minimum size - if (size < sizeof(chip32_binary_header_t)) { - out_loaded->error = CHIP32_BIN_ERR_TOO_SMALL; + if (binary_size < sizeof(chip32_binary_header_t)) { return CHIP32_BIN_ERR_TOO_SMALL; } // Copy header - memcpy(&out_loaded->header, binary, sizeof(chip32_binary_header_t)); + memcpy(&header, binary, sizeof(chip32_binary_header_t)); // Verify magic number - if (out_loaded->header.magic != CHIP32_MAGIC) { - out_loaded->error = CHIP32_BIN_ERR_INVALID_MAGIC; + if (header.magic != CHIP32_MAGIC) { return CHIP32_BIN_ERR_INVALID_MAGIC; } // Check version - if (out_loaded->header.version > CHIP32_VERSION) { - out_loaded->error = CHIP32_BIN_ERR_UNSUPPORTED_VERSION; + if (header.version > CHIP32_VERSION) { return CHIP32_BIN_ERR_UNSUPPORTED_VERSION; } // Calculate expected size uint32_t expected_size = sizeof(chip32_binary_header_t) + - out_loaded->header.data_size + - out_loaded->header.code_size + - out_loaded->header.init_data_size; + header.const_size + + header.code_size + + header.init_data_size; - if (size != expected_size) { - out_loaded->error = CHIP32_BIN_ERR_SIZE_MISMATCH; + if (binary_size != expected_size) { return CHIP32_BIN_ERR_SIZE_MISMATCH; } // Set section pointers uint32_t offset = sizeof(chip32_binary_header_t); - - if (out_loaded->header.data_size > 0) { - out_loaded->data_section = binary + offset; - offset += out_loaded->header.data_size; - } - - if (out_loaded->header.code_size > 0) { - out_loaded->code_section = binary + offset; - offset += out_loaded->header.code_size; - } - - if (out_loaded->header.init_data_size > 0) { - out_loaded->init_data_section = binary + offset; - } - - out_loaded->error = CHIP32_BIN_OK; - return CHIP32_BIN_OK; -} -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->bss_size = loaded->header.bss_size; - out_stats->code_size = loaded->header.code_size; - out_stats->init_data_size = loaded->header.init_data_size; + // Skip header for ROM executable (must start at a valide code address) + ctx->rom.mem = binary + offset; + ctx->rom.size = binary_size - offset; + ctx->rom.addr = 0; + + // RAM and ROM are in the same logical memory plane + // So we set it begin after the ROM (why not) + ctx->ram.mem = ram; + ctx->ram.addr = ctx->rom.size; + ctx->ram.size = ram_size; + + // Set entry point (DATA size + entry point offset in CODE) + ctx->registers[PC] = header.entry_point; + + // Load data initialized values + const uint8_t *data = binary + header.code_size; + memcpy(ram, data, header.init_data_size); + + + out_stats->const_size = header.const_size; + out_stats->bss_size = header.bss_size; + out_stats->code_size = header.code_size; + out_stats->init_data_size = header.init_data_size; out_stats->total_file_size = sizeof(chip32_binary_header_t) + - loaded->header.data_size + - loaded->header.code_size + - loaded->header.init_data_size; + header.const_size + + header.code_size + + header.init_data_size; - out_stats->total_rom_size = loaded->header.data_size + - loaded->header.code_size; + out_stats->total_rom_size = header.const_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) @@ -146,7 +144,7 @@ uint32_t chip32_binary_calculate_size(const chip32_binary_header_t* header) } return sizeof(chip32_binary_header_t) + - header->data_size + + header->const_size + header->code_size + header->init_data_size; } @@ -178,12 +176,12 @@ uint32_t chip32_binary_write( offset += sizeof(chip32_binary_header_t); // Write DATA section - if (header->data_size > 0) { + if (header->const_size > 0) { if (!data_section) { return 0; // Data expected but NULL pointer } - memcpy(out_buffer + offset, data_section, header->data_size); - offset += header->data_size; + memcpy(out_buffer + offset, data_section, header->const_size); + offset += header->const_size; } // Write CODE section @@ -207,35 +205,6 @@ uint32_t chip32_binary_write( 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 @@ -260,7 +229,7 @@ void chip32_binary_print_header(const chip32_binary_header_t* header) printf(" (has init data)"); } 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("CODE section: %u bytes\n", header->code_size); 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("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("CODE section: %u bytes (ROM, executable)\n", stats->code_size); printf("Init data: %u bytes (RAM initialization)\n", stats->init_data_size); diff --git a/core/chip32/chip32_binary_format.h b/core/chip32/chip32_binary_format.h index 13f469a..e316604 100644 --- a/core/chip32/chip32_binary_format.h +++ b/core/chip32/chip32_binary_format.h @@ -37,6 +37,24 @@ * - Initial RAM values: DV values + zeros for DZ areas * - Size = sum of all DV and DZ declarations * - 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 @@ -44,6 +62,7 @@ #include #include +#include "chip32_vm.h" #ifdef __cplusplus extern "C" { @@ -74,7 +93,7 @@ typedef struct { uint32_t magic; // Magic number "C32\0" uint16_t version; // Format version 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 code_size; // Size of CODE section in bytes uint32_t entry_point; // Entry point offset in CODE section @@ -82,18 +101,9 @@ typedef struct { } chip32_binary_header_t; #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 typedef struct { - uint32_t data_size; // ROM constants + uint32_t const_size; // ROM constants uint32_t bss_size; // Total RAM needed uint32_t code_size; // Executable code uint32_t init_data_size; // RAM initialization data @@ -114,20 +124,14 @@ typedef struct { * @return Error code */ chip32_binary_error_t chip32_binary_load( + chip32_ctx_t *ctx, uint8_t* binary, - uint32_t size, - chip32_loaded_binary_t* out_loaded + uint32_t binary_size, + 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 @@ -156,7 +160,7 @@ uint32_t chip32_binary_calculate_size(const chip32_binary_header_t* header); /** * Write a complete binary to memory * @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 init_data_section INIT DATA section (can be NULL if init_data_size is 0) * @param out_buffer Output buffer (must be large enough) @@ -172,24 +176,6 @@ uint32_t chip32_binary_write( 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 // ============================================================================ diff --git a/core/chip32/chip32_machine.h b/core/chip32/chip32_machine.h index 413ef85..79d5b93 100644 --- a/core/chip32/chip32_machine.h +++ b/core/chip32/chip32_machine.h @@ -34,6 +34,7 @@ public: m_syscallHandler = std::bind(&Machine::HandleSyscall, this, std::placeholders::_1, std::placeholders::_2); + m_ram.resize(1024); } // ======================================================================== @@ -64,12 +65,15 @@ public: result.Print(); - // Load binary using new format - chip32_loaded_binary_t loaded; + // Load binary using executable format + chip32_binary_stats_t stats; chip32_binary_error_t error = chip32_binary_load( + &ctx, program.data(), static_cast(program.size()), - &loaded + m_ram.data(), + static_cast(m_ram.size()), + &stats ); if (error != CHIP32_BIN_OK) { @@ -78,29 +82,6 @@ public: 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 ctx.syscall = SyscallWrapper; ctx.user_data = this; @@ -108,8 +89,6 @@ public: // Initialize VM 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::dec << std::endl; @@ -281,14 +260,7 @@ public: uint8_t *ram_buffer, 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(binary.size()), - &loaded - ); - + if (err != CHIP32_BIN_OK) { std::cerr << "Binary load error: " << chip32_binary_error_string(err) << std::endl; diff --git a/core/chip32/chip32_vm.c b/core/chip32/chip32_vm.c index a0727d9..3b2fb1a 100644 --- a/core/chip32/chip32_vm.c +++ b/core/chip32/chip32_vm.c @@ -104,14 +104,14 @@ void chip32_initialize(chip32_ctx_t *ctx) { memset(ctx->ram.mem, 0, ctx->ram.size); memset(ctx->registers, 0, REGISTER_COUNT * sizeof(uint32_t)); - ctx->instrCount = 0; + ctx->instr_count = 0; ctx->registers[SP] = ctx->ram.size; } chip32_result_t chip32_run(chip32_ctx_t *ctx) { 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); @@ -434,7 +434,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx) } ctx->registers[PC]++; - ctx->instrCount++; + ctx->instr_count++; return result; } diff --git a/core/chip32/chip32_vm.h b/core/chip32/chip32_vm.h index 7bba2e7..fc31078 100644 --- a/core/chip32/chip32_vm.h +++ b/core/chip32/chip32_vm.h @@ -208,7 +208,7 @@ struct chip32_ctx_t virtual_mem_t rom; virtual_mem_t ram; uint16_t stack_size; - uint32_t instrCount; + uint32_t instr_count; uint16_t prog_size; uint32_t max_instr; uint32_t registers[REGISTER_COUNT]; diff --git a/core/tests/test_parser.cpp b/core/tests/test_parser.cpp index f1aedb1..fd4c1ac 100644 --- a/core/tests/test_parser.cpp +++ b/core/tests/test_parser.cpp @@ -363,7 +363,7 @@ TEST_CASE("Binary format validation") REQUIRE(loaded.header.magic == CHIP32_MAGIC); REQUIRE(loaded.header.version == CHIP32_VERSION); 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.code_size > 0); // Has code REQUIRE(loaded.header.init_data_size == loaded.header.bss_size); // Must match diff --git a/core/tests/test_vm.cpp b/core/tests/test_vm.cpp index 6f5b888..f214baf 100644 --- a/core/tests/test_vm.cpp +++ b/core/tests/test_vm.cpp @@ -24,59 +24,37 @@ THE SOFTWARE. #include #include "catch.hpp" -#include "chip32_assembler.h" -#include "chip32_vm.h" +#include "chip32_machine.h" // Inclure chip32_machine.h au lieu de assembler et vm /* Purpose: test all opcodes */ -void hexdump(void *ptr, int buflen); - -static uint8_t story_player_syscall(chip32_ctx_t *ctx, uint8_t code) -{ - uint8_t retCode = SYSCALL_RET_OK; - - return retCode; -} - +// Suppression des fonctions et classes de configuration de la VM +// qui sont maintenant encapsulées dans Chip32::Machine. class VmTestContext { public: 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) { - // --------- BUILD BINARY --------- - REQUIRE( assembler.Parse(assemblyCode) == true ); - REQUIRE( assembler.BuildBinary(program, result) == true ); - result.Print(); + // Utiliser la méthode QuickExecute de Machine pour Parse, Build et Run + machine.QuickExecute(assemblyCode); - 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(); - chip32_ctx.rom.addr = 18*1024; - 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 ); + // Vérification que l'exécution a fini normalement (HALT) + REQUIRE( machine.runResult == VM_FINISHED ); } - uint8_t data[8*1024]; - std::vector program; - Chip32::Assembler assembler; - Chip32::Result result; - chip32_ctx_t chip32_ctx; + Chip32::Machine machine; // Instance de la Machine à utiliser pour les tests }; @@ -89,7 +67,8 @@ TEST_CASE_METHOD(VmTestContext, "MUL", "[vm]") { )"; 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); } @@ -102,6 +81,7 @@ TEST_CASE_METHOD(VmTestContext, "DIV", "[vm]") { )"; 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)); }